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.