Basic templating engine in F# using F# syntax
There are a few suggestions which immediately occur to me:  some are minor changes which could improve the clarity of the code and there is one major change which would shorten the code quite a bit.

The minor changes:


For List.fold you can just pass a function which matches the expected type and not write the full lambda.  With an operator like + it's not obvious, but you can clean up your code a bit using:

attrs
|&gt; List.map (fun (name,value) -&gt; sprintf "%s=\"%s\"" name value)
|&gt; List.fold (+) ""

In the function childContent, I would move the call to expandTree into a List.map, to reduce the amount of nesting and to allow us to clean up the List.fold:

children
|&gt; List.map (fun child -&gt; expandTree child [])
|&gt; List.fold (@) []

With Text(string) you should use a name other than string since that's the name of an existing type and that could cause confusion for someone reading your code.


The major change is that you can combine the tokenWriter and the expandTree into a single function.  At the heart, what you are doing is an in order traversal of a tree to convert your HTML structure into a string:  expandTree does an in order traversal to flatten the tree into a list and then tokenWriter converts those tokens into strings.  You're not gaining much by flattening the tree and then generating the output string; so, you could just use the tree traversal to generate the output string.

Making this change also allows you to remove the Token type, further reducing the overall complexity of your code.

Here's the updated code:

    let Template el =
        let rec elementToString el output = 
            let attributesToString attrs =
                attrs
                |&gt; List.map (fun (name,value) -&gt; sprintf "%s=\"%s\"" name value)
                |&gt; List.fold (+) ""

            match el with
            | Tag(tagName, attrs, children) -&gt; 
                let attributes = attributesToString attrs
                let tagStr = sprintf "&lt;%s%s&gt;" tagName attributes
                let childContent = 
                    children
                    |&gt; List.map (fun item -&gt; elementToString item "" )
                    |&gt; List.fold (+) tagStr
                let closeTagStr = sprintf "&lt;/%s&gt;" tagName
                sprintf "%s%s%s" output childContent closeTagStr
            | TagSelfClosing(tagName, attrs) -&gt;
                let attributes = attributesToString attrs
                sprintf "%s&lt;%s%s /&gt;" output tagName attributes
            | Collection(elements) -&gt;
                elements
                |&gt; List.map (fun e -&gt; elementToString e output)
                |&gt; List.fold (+) ""
            | Text(text) -&gt;
                sprintf "%s%s" output text

        let expandedTree = elementToString el ""
        let content = 
            expandedTree

        printf "%s" content