ZetCode

F# Verbose Syntax

last modified May 24, 2025

This article explores verbose syntax in F#, which provides explicit syntax rules for situations where lightweight syntax might be ambiguous.

F# supports two syntax variants: lightweight and verbose. Verbose syntax requires more keywords but can resolve ambiguities in complex code. It's particularly useful in interface implementations, type extensions, and certain expressions.

Verbose syntax is always available, allowing you to use it alongside lightweight syntax for certain constructs. While not as commonly used, verbose syntax offers the benefit of being less dependent on indentation, making it more forgiving in structured code layouts.

The main differences include using in keywords after bindings, explicit then in conditionals, and done in loops.

Enabling verbose syntax

Verbose syntax can be enabled for entire files or specific code sections.

main.fsx
let add x y = 
    begin
        x + y
    end

printfn "Result: %d" (add 5 3)

This example shows verbose syntax in a function definition.

let add x y = 
    begin
        x + y
    end

The begin and end keywords explicitly mark the function body, which is a requirement in verbose syntax.

λ dotnet fsi main.fsx
Result: 8

Let bindings in verbose syntax

Verbose syntax requires the in keyword for sequential let bindings.

main.fsx
let calculate x y =
    let sum = x + y in
    let product = x * y in
    sum, product

let result = calculate 3 4
printfn "Sum: %d, Product: %d" (fst result) (snd result)

This demonstrates verbose let bindings with mandatory in keywords.

let sum = x + y in
let product = x * y in

Each let binding requires an in keyword to separate it from the following expression in verbose mode.

λ dotnet fsi main.fsx
Sum: 7, Product: 12

Loops in verbose syntax

Loop constructs require additional keywords in verbose mode.

main.fsx
let printNumbers n =
    let mutable i = 1
    while i <= n do
        printf "%d " i
        i <- i + 1
    done
    printfn ""

printNumbers 5

This example demonstrates a while loop with verbose syntax requirements.

while i <= n do
    printf "%d " i
    i <- i + 1
done

The done keyword is required to mark the end of the loop body in verbose syntax.

λ dotnet fsi main.fsx
1 2 3 4 5 

Type definitions

Verbose syntax affects how types are defined and implemented.

main.fsx
type Shape =
    | Circle of radius: float
    | Rectangle of width: float * height: float
    with
        member this.Area =
            match this with
            | Circle r -> System.Math.PI * r * r
            | Rectangle (w, h) -> w * h
        end

let circle = Circle(5.0)
let rect = Rectangle(4.0, 6.0)

printfn "Circle area: %.2f" circle.Area
printfn "Rectangle area: %.2f" rect.Area

This shows type definitions with verbose syntax markers.

with
    member this.Area =
        match this with
        | Circle r -> System.Math.PI * r * r
        | Rectangle (w, h) -> w * h
    end

The with and end keywords explicitly delimit the member definitions.

λ dotnet fsi main.fsx
Circle area: 78.54
Rectangle area: 24.00

Module definitions

Modules in verbose syntax require explicit begin/end markers.

main.fsx
module MathOperations =
    begin
        let add x y = x + y
        let subtract x y = x - y
    end

printfn "Addition: %d" (MathOperations.add 10 5)
printfn "Subtraction: %d" (MathOperations.subtract 10 5)

This demonstrates module definition with verbose syntax requirements.

module MathOperations =
    begin
        let add x y = x + y
        let subtract x y = x - y
    end

The begin and end keywords explicitly delimit the module contents.

λ dotnet fsi main.fsx
Addition: 15
Subtraction: 5

Implementing Interfaces with Verbose Syntax

When implementing interfaces, verbose syntax provides a structured way to define members. This is particularly useful when the interface has multiple members or when the implementation requires clarity in complex scenarios.

main.fsx
type IDisplayer =
    abstract member Display : string -> unit

type ConsoleDisplayer() =
    interface IDisplayer with
        begin
            member this.Display msg =
                begin
                    printfn "Message: %s" msg
                end
        end

let displayer = ConsoleDisplayer() :> IDisplayer
displayer.Display "Hello from verbose syntax"

The interface implementation is enclosed within a begin/end block. The member implementation for Display is also wrapped in begin/end.

λ dotnet fsi main.fsx
Message: Hello from verbose syntax

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.