Text Templates in F#

Our first program demonstrates the use of text templates in F#. Here’s the full source code:

open System
open System.IO

// We can create a new template and parse its body from a string.
// Templates are a mix of static text and "actions" enclosed in
// {{...}} that are used to dynamically insert content.
let t1 = 
    let template = "Value is {{value}}\n"
    let compiled = template.Replace("{{value}}", "%s")
    fun value -> Printf.sprintf compiled value

// By "executing" the template we generate its text with
// specific values for its actions.
printfn "%s" (t1 "some text")
printfn "%s" (t1 "5")
printfn "%s" (t1 (String.Join(", ", ["F#"; "C#"; "OCaml"; "Haskell"])))

// If the data is a record we can use the {{FieldName}} action to access
// its fields.
type Person = { Name: string }

let t2 = 
    let template = "Name: {{Name}}\n"
    let compiled = template.Replace("{{Name}}", "%s")
    fun (p: Person) -> Printf.sprintf compiled p.Name

printfn "%s" (t2 { Name = "Jane Doe" })

// The same applies to maps; with maps there is no restriction on the
// case of key names.
let personMap = Map.ofList [("Name", "Mickey Mouse")]
printfn "%s" (t2 { Name = personMap.["Name"] })

// if/else provide conditional execution for templates. A value is considered
// false if it's None, false, or an empty string.
let t3 = 
    let template = "{{if value}} yes {{else}} no {{endif}}\n"
    let compiled = template.Replace("{{if value}}", "%s").Replace("{{else}}", "%s").Replace("{{endif}}", "")
    fun value -> 
        match value with
        | "" -> Printf.sprintf compiled "no" ""
        | _ -> Printf.sprintf compiled "yes" ""

printfn "%s" (t3 "not empty")
printfn "%s" (t3 "")

// range blocks let us loop through lists or arrays. Inside
// the range block {{.}} is set to the current item of the iteration.
let t4 = 
    let template = "Range: {{range items}}{{.}} {{endrange}}\n"
    let compiled = template.Replace("{{range items}}", "%s").Replace("{{endrange}}", "")
    fun (items: string list) -> 
        Printf.sprintf compiled (String.Join(" ", items))

printfn "%s" (t4 ["F#"; "OCaml"; "Haskell"; "Scala"])

To run the program, save it as TextTemplates.fs and use the F# compiler:

$ fsharpc TextTemplates.fs
$ mono TextTemplates.exe
Value is some text
Value is 5
Value is F#, C#, OCaml, Haskell
Name: Jane Doe
Name: Mickey Mouse
yes 
no 
Range: F# OCaml Haskell Scala 

This example demonstrates how to create and use text templates in F#. While F# doesn’t have a built-in templating engine like Go’s text/template, we can achieve similar functionality using string manipulation and functions.

The code shows how to create template functions that accept different types of data (strings, records, maps) and how to implement conditional logic and loops within templates. The F# version uses pattern matching and higher-order functions to mimic the behavior of Go’s templating system.

Note that this is a simplified version and doesn’t include all the features of a full-fledged templating engine. For more complex templating needs in F#, you might want to consider using a dedicated templating library.