ZetCode

F# string interpolation

last modified May 17, 2025

In this article we will explore string interpolation in F#.

String interpolation in F# provides a concise way to embed expressions within string literals. Interpolated strings are prefixed with $ and contain expressions wrapped in {}. This feature allows for dynamic string construction, making it easier to create formatted strings without the need for cumbersome concatenation or formatting functions.

Basic string interpolation

F# string interpolation allows embedding variables and expressions directly in strings:

basic_interpolation.fsx
let name = "John Doe"
let age = 34

printfn $"{name} is {age} years old"

let now = System.DateTime.Now
printfn $"""Today is {now.DayOfWeek}, it's {now.ToString("HH:mm")}"""

This example shows simple variable interpolation and datetime formatting. The $ prefix marks an interpolated string, with expressions in {}.

λ dotnet fsi basic_interpolation.fsx
John Doe is 34 years old
Today is Sunday, it's 11:58

Typed string interpolation

F# supports typed interpolated strings with format specifiers for type safety:

typed_interpolation.fsx
let name = "John Doe"
let age = 34

printfn $"Name: %s{name}, Age: %d{age}"

let price = 49.99
let quantity = 3
printfn $"Total: %f{price * float quantity}"

Format specifiers (%s for string, %d for int, %f for float) ensure type safety and proper formatting.

λ dotnet fsi typed_interpolation.fsx
Name: John Doe, Age: 34
Total: 149.970000

Format strings

Interpolated strings support .NET format strings for numbers and dates:

format_strings.fsx
let now = System.DateTime.Now

printfn $"Short date: {now:d}"
printfn $"Long date: {now:D}"
printfn $"Short time: {now:t}"
printfn $"Long time: {now:T}"

let value = 1234.5678
printfn $"Currency: {value:C}"
printfn $"Scientific: {value:E2}"
printfn $"Fixed-point: {value:F2}"

Standard .NET format specifiers work within interpolated expressions.

λ dotnet fsi format_strings.fsx
Short date: 19. 1. 2024
Long date: Friday, January 19, 2024
Short time: 11:19
Long time: 11:19:22
Currency: $1,234.57
Scientific: 1.23E+003
Fixed-point: 1234.57

Alignment and padding

Values can be aligned within interpolated strings using alignment specifiers:

alignment.fsx
type User = { FirstName: string; LastName: string; Salary: int }

let users = [
    { FirstName = "John"; LastName = "Doe"; Salary = 1230 }
    { FirstName = "Lucy"; LastName = "Novak"; Salary = 670 }
    { FirstName = "Ben"; LastName = "Walter"; Salary = 2050 }
]

for user in users do
    let name = $"{user.FirstName} {user.LastName}"
    printfn $"|{name,-15}|{user.Salary,8}|"

Negative alignment left-aligns, positive right-aligns. The number specifies total width.

λ dotnet fsi alignment.fsx
|John Doe       |    1230|
|Lucy Novak     |     670|
|Ben Walter     |    2050|

Expressions in interpolation

Complex expressions can be embedded in interpolated strings:

expressions.fsx
let x = 5
let y = 10

printfn $"Sum: {x + y}"
printfn $"Product: {x * y}"
printfn $"""Comparison: {if x < y then "x < y" else "x >= y"}"""

let numbers = [1..5]
printfn $"Count: {numbers.Length}, Sum: {List.sum numbers}"

Any valid F# expression can be used within the interpolation braces.

λ dotnet fsi expressions.fsx
Sum: 15
Product: 50
Comparison: x < y
Count: 5, Sum: 15

Multiline interpolated strings

F# supports multiline interpolated strings with triple-quote syntax:

multiline.fsx
let name = "Alice"
let score = 95

let grade = if score >= 90 then "A" else "B"
let status = if score >= 70 then "PASS" else "FAIL"

let message = $"""
    Report for {name}:
    - Score: {score}
    - Grade: {grade}
    - Status: {status}
    """

printfn "%s" message

Triple quotes preserve indentation and newlines in the string literal.

λ dotnet fsi multiline.fsx
Report for Alice:
- Score: 95
- Grade: A
- Status: PASS

Verbatim Interpolated Strings

In F#, interpolated strings $"..." allow variable substitution, while verbatim strings @"..." preserve escape sequences like backslashes.

To correctly format paths, use a verbatim string for backslashes and an interpolated string separately for substitutions:

verbatim.fsx
let path = @"C:\Users\John"  // Verbatim string (preserves backslashes)
let file = "document.txt"

let fullPath = $"Full path: {path}\\{file}"  // Double backslash to escape in interpolated string

printfn "%s" fullPath

Verbatim strings are useful for handling file paths, regex patterns, and escaping sequences, while interpolated strings simplify variable substitution.

λ dotnet fsi verbatim.fsx
Full path: C:\Users\John\document.txt

Interpolated strings with collections

Collections can be processed within interpolated strings:

collections.fsx
let fruits = ["apple"; "banana"; "orange"]

printfn $"""Fruits: {String.concat ", " fruits}"""
printfn $"Count: {List.length fruits}"
printfn $"First: {List.head fruits}"

let numbers = [1..5]
printfn $"Sum: {List.sum numbers}, Avg: {List.averageBy float numbers}"

Collection operations work naturally within interpolated expressions.

λ dotnet fsi collections.fsx
Fruits: apple, banana, orange
Count: 3
First: apple
Sum: 15, Avg: 3.0

Conditional formatting

Conditional logic can be used within interpolated strings:

conditional.fsx
let items = [
    "ring", 2
    "lamp", 1
    "chair", 3
]

for (name, count) in items do
    printfn $"""{count} {name}{if count = 1 then "" else "s"}"""

let temp = 22.5
printfn $"""Temperature: {temp}°C ({if temp > 20.0 then "Warm" else "Cool"})"""

Parentheses help separate the conditional operator from format strings.

λ dotnet fsi conditional.fsx
2 rings
1 lamp
3 chairs
Temperature: 22.5°C (Warm)

Best practices

Follow these guidelines for effective string interpolation:

best_practices.fsx
// 1. Use typed interpolation for safety
let userId = "A123"
let attempts = 3
printfn $"User %s{userId} has %d{attempts} attempts left"

// 2. Keep complex logic outside strings
let calculateTotal price qty = price * float qty
let itemPrice = 12.99
let quantity = 5
printfn $"Total: {calculateTotal itemPrice quantity:C}"

// 3. Format for readability
let data = [(1, "A"); (2, "B"); (3, "C")]
for (id, value) in data do
    printfn $"|{id,3}|{value,-5}|"

// 4. Prefer interpolation over concatenation
let name = "Alice"
let age = 30
// Good:
printfn $"Name: {name}, Age: {age}"
// Avoid:
printfn "%s" ("Name: " + name + ", Age: " + string age)

F# string interpolation provides a powerful way to create strings with embedded expressions. The $ prefix enables easy variable insertion, while typed interpolation (%s, %d) ensures type safety. Multiline and verbatim strings handle complex formatting needs, making string construction cleaner and more maintainable.

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.