Interpolated strings

Interpolated strings are strings that allow you to embed F# expressions into them. They are helpful in a wide range of scenarios where the value of a string may change based on the result of a value or expression.

Syntax

$"string-text {expr}"
$"string-text %format-specifier{expr}"
$"""string-text {"embedded string literal"}"""
$$"""string-text %%format-specifier{{expr}}"""

Remarks

Interpolated strings let you write code in "holes" inside of a string literal. Here's a basic example:

let name = "Phillip"
let age = 30
printfn $"Name: {name}, Age: {age}"

printfn $"I think {3.0 + 0.14} is close to {System.Math.PI}!"

The contents in between each {} brace pair can be any F# expression.

To escape a {} brace pair, write two of them like so:

let str = $"A pair of braces: {{}}"
// "A pair of braces: {}"

Typed interpolated strings

Interpolated strings can also have F# format specifiers to enforce type safety.

let name = "Phillip"
let age = 30

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

// Error: type mismatch
printfn $"Name: %s{age}, Age: %d{name}"

In the previous example, the code mistakenly passes the age value where name should be, and vice/versa. Because the interpolated strings use format specifiers, this is a compile error instead of a subtle runtime bug.

Verbatim interpolated strings

F# supports verbatim interpolated strings with triple quotes so that you can embed string literals.

let age = 30

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

Format specifiers

Format specifiers can either be printf-style or .NET-style. Printf-style specifiers are those covered in plaintext formatting, placed before the braces. For example:

let pi = $"%0.3f{System.Math.PI}"  // "3.142"
let code = $"0x%08x{43962}"  // "0x0000abba"

The format specifier %A is particularly useful for producing diagnostic output of structured F# data.

let data = [0..4]
let output = $"The data is %A{data}"  // "The data is [0; 1; 2; 3; 4]"

.NET-style specifiers are those usable with String.Format, placed after a : within the braces. For example:

let pi = $"{System.Math.PI:N4}"  // "3.1416"
let now = $"{System.DateTime.UtcNow:``yyyyMMdd``}" // e.g. "20220210"

If a .NET-style specifier contains an unusual character, then it can be escaped using double-backticks:

let nowDashes = $"{System.DateTime.UtcNow:``yyyy-MM-dd``}" // e.g. "2022-02-10"

Aligning expressions in interpolated strings

You can left-align or right-align expressions inside interpolated strings with | and a specification of how many spaces. The following interpolated string aligns the left and right expressions to the left and right, respectively, by seven spaces.

printfn $"""|{"Left",-7}|{"Right",7}|"""
// |Left   |  Right|

Interpolated strings and FormattableString formatting

You can also apply formatting that adheres to the rules for FormattableString:

let speedOfLight = 299792.458
printfn $"The speed of light is {speedOfLight:N3} km/s."
// "The speed of light is 299,792.458 km/s."

Additionally, an interpolated string can also be type checked as a FormattableString via a type annotation:

let frmtStr = $"The speed of light is {speedOfLight:N3} km/s." : FormattableString
// Type: FormattableString
// The speed of light is 299,792.458 km/s.

Note that the type annotation must be on the interpolated string expression itself. F# does not implicitly convert an interpolated string into a FormattableString.

Extended syntax for string interpolation

Beginning with F# 8, when you work with text containing multiple {, } or % characters already, you can use extended string interpolation syntax to remove the need for escaping.

Triple quote string literals can start with multiple $ characters, which changes how many braces are required to open and close interpolation. In these string literals, { and } characters don't need to be escaped:

let str = $$"""A string containing some {curly braces} and an {{"F#" + " " + "expression"}}."""
// "A string containing some {curly braces} and an F# expression."
let another = $$$"""A string with pairs of {{ and }} characters and {{{ "an F# expression" }}}."""
// "A string with pairs of {{ and }} characters and an F# expression."""

The number of % characters needed for format specifiers is affected in the same way:

let percent = $$"""50% of 20 is %%.1f{{20m * 0.5m}}"""
// "50% of 20 is 10.0"

See also