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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
// 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.