Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Výpočetní výrazy v jazyce F# poskytují pohodlnou syntaxi pro psaní výpočtů, které lze sekvencovat a kombinovat pomocí konstruktorů a vazeb toku řízení. V závislosti na druhu výpočetního výrazu je možné je považovat za způsob vyjádření monadů, monoidů, transformátorů monadů a aplikačních funktorů. Na rozdíl od jiných jazyků (například do-notation v Haskellu) však nejsou svázané s jedinou abstrakcí a nespoléhají se na makra nebo jiné formy metaprogramování, aby bylo možné dosáhnout pohodlnou a kontextově citlivou syntaxi.
Přehled
Výpočty můžou mít mnoho forem. Nejběžnější formou výpočtu je provádění s jedním vláknem, což je snadné pochopit a upravit. Ne všechny formy výpočtů jsou ale stejně jednoduché jako provádění s jedním vláknem. Mezi příklady patří:
- Ne deterministické výpočty
- Asynchronní výpočty
- Efektní výpočty
- Generativní výpočty
Obecně platí, že existují výpočty citlivé na kontext , které musíte provést v určitých částech aplikace. Psaní kódu citlivého na kontext může být náročné, protože bez abstrakcí je snadné, aby se výpočty "uklouzly" mimo daný kontext. Tyto abstrakce jsou často náročné psát sami, což je důvod, proč jazyk F# má zobecněný způsob, jak to udělat, označované jako výpočetní výrazy.
Výpočetní výrazy nabízejí jednotný model syntaxe a abstrakce pro výpočty citlivé na kontext kódování.
Každý výpočetní výraz je podporován typem tvůrce . Typ tvůrce definuje operace, které jsou k dispozici pro výpočetní výraz. Viz Vytvoření nového typu výpočetního výrazu, který ukazuje, jak vytvořit vlastní výpočetní výraz.
Přehled syntaxe
Všechny výpočetní výrazy mají následující tvar:
builder-expr { cexper }
V této formě je builder-expr název typu tvůrce, který definuje výpočetní výraz, a cexper je tělo výpočetního výrazu. Například async kód výpočetního výrazu může vypadat takto:
let fetchAndDownload url =
async {
let! data = downloadData url
let processedData = processData data
return processedData
}
Ve výrazu výpočtu je k dispozici speciální další syntaxe, jak je znázorněno v předchozím příkladu. Následující formuláře výrazů jsou možné s výpočetními výrazy:
expr { let! ... }
expr { and! ... }
expr { do! ... }
expr { yield ... }
expr { yield! ... }
expr { return ... }
expr { return! ... }
expr { match! ... }
Každé z těchto klíčových slov a další standardní klíčová slova jazyka F# jsou k dispozici pouze ve výpočetním výrazu, pokud byly definovány v typu backing builderu. Jedinou výjimkou je match!, což je samo o sobě syntaktický cukr pro použití let! následované vzorovou shodou s výsledkem.
Typ tvůrce je objekt, který definuje speciální metody, které řídí způsob kombinování fragmentů výpočetního výrazu; to znamená, že jeho metody řídí chování výpočetního výrazu. Dalším způsobem, jak popsat třídu builderu, je říct, že umožňuje přizpůsobit činnost mnoha konstrukcí jazyka F#, jako jsou smyčky a přiřazení.
let!
Klíčové let! slovo sváže výsledek volání na jiný výpočetní výraz s názvem:
let doThingsAsync url =
async {
let! data = getDataAsync url
...
}
Pokud svážete volání s výpočetním výrazem let, nedostanete výsledek výpočetního výrazu. Místo toho budete mít vázanou hodnotu nerealizovaného volání na tento výpočetní výraz. Použijte let! k vytvoření vazby na výsledek.
let! je definován členem Bind(x, f) typu tvůrce.
and!
Klíčové and! slovo umožňuje efektivněji svázat výsledky více volání výpočetních výrazů. Toto klíčové slovo umožňuje aplikativní výpočetní výrazy, které poskytují jiný výpočetní model než standardní monadický přístup.
let doThingsAsync url =
async {
let! data = getDataAsync url
and! moreData = getMoreDataAsync anotherUrl
and! evenMoreData = getEvenMoreDataAsync someUrl
...
}
Pomocí řady let! ... let! ... provádění výpočtů postupně, i když jsou nezávislé. Naproti tomu indikuje, let! ... and! ... že výpočty jsou nezávislé, což umožňuje použití kombinace. Tato nezávislost umožňuje autorům výpočetních výrazů:
- Provádění výpočtů efektivněji.
- Může paralelně spouštět výpočty.
- Kumulujte výsledky bez zbytečných sekvenčních závislostí.
Omezení spočívá v tom, že výpočty v kombinaci s and! nemožností záviset na výsledcích dříve vázaných hodnot ve stejném let!/and! řetězci. Tento kompromis umožňuje výhody výkonu.
and! je určován především členem MergeSources(x1, x2) typu tvůrce.
Volitelně lze definovat MergeSourcesN(x1, x2 ..., xN) pro snížení počtu uzlů spojování, a BindN(x1, x2 ..., xN, f) nebo BindNReturn(x1, x2, ..., xN, f) lze definovat, aby efektivně svázaly výsledky výpočetních výrazů bez použití uzlů spojování.
Další informace o aplikativních výpočetních výrazech najdete v tématu Aplikační výpočetní výrazy v jazyce F# 5 a F# RFC FS-1063.
do!
Klíčové slovo do! je pro volání výpočetního výrazu, který vrací typ podobný unit (definovaný Zero členem tvůrce).
let doThingsAsync data url =
async {
do! submitData data url
...
}
Pro asynchronní pracovní postup je Async<unit>tento typ . U jiných výpočetních výrazů bude typ pravděpodobně CExpType<unit>.
do! je definován členem Bind(x, f) typu builder, kde f vytvoří unit.
yield
Klíčové yield slovo je pro vrácení hodnoty z výpočetního výrazu, aby bylo možné ho použít jako IEnumerable<T>:
let squares =
seq {
for i in 1..10 do
yield i * i
}
for sq in squares do
printfn $"%d{sq}"
Ve většině případů ho můžou volající vynechat. Nejběžnější způsob, jak vynechat yield , je operátor -> :
let squares =
seq {
for i in 1..10 -> i * i
}
for sq in squares do
printfn $"%d{sq}"
U složitějších výrazů, které by mohly přinést mnoho různých hodnot, a možná podmíněně, stačí, když klíčové slovo vynecháte:
let weekdays includeWeekend =
seq {
"Monday"
"Tuesday"
"Wednesday"
"Thursday"
"Friday"
if includeWeekend then
"Saturday"
"Sunday"
}
Stejně jako u klíčového slova yield v jazyce C# je každý prvek ve výpočetním výrazu vrácen, když je iterován.
yield je definován Yield(x) členem typu tvůrce, kde x je položka, která se má vrátit zpět.
yield!
Klíčové slovo yield! slouží k usnadnění práce s kolekcí hodnot ve výpočetním výrazu.
let squares =
seq {
for i in 1..3 -> i * i
}
let cubes =
seq {
for i in 1..3 -> i * i * i
}
let squaresAndCubes =
seq {
yield! squares
yield! cubes
}
printfn $"{squaresAndCubes}" // Prints - 1; 4; 9; 1; 8; 27
Při vyhodnocení se výpočetní výraz volaný přes yield! vrátí položky jednu po druhé, což zploští výsledek.
yield! je definován členem YieldFrom(x) typu tvůrce, kde x je kolekce hodnot.
Na rozdíl od yield, yield! musí být explicitně zadán. Jeho chování není implicitní ve výpočetních výrazech.
return
Klíčové return slovo zabalí hodnotu v typu odpovídající výpočetnímu výrazu. Kromě výpočetních výrazů, které používají yield, se používá k "dokončení" výpočetního výrazu:
let req = // 'req' is of type 'Async<data>'
async {
let! data = fetch url
return data
}
// 'result' is of type 'data'
let result = Async.RunSynchronously req
return je definován členem Return(x) u typu sestavovače, přičemž x je položka, která se má zabalit. Pro lepší výkon lze použít let! ... return pro použití BindReturn(x, f).
return!
Klíčové return! slovo vyhodnotí hodnotu výpočetního výrazu a uzavře tento výsledek do typu odpovídajícího výpočetnímu výrazu:
let req = // 'req' is of type 'Async<data>'
async {
return! fetch url
}
// 'result' is of type 'data'
let result = Async.RunSynchronously req
return! je definován členem ReturnFrom(x) typu tvůrce, kde x je další výpočetní výraz.
match!
Klíčové match! slovo umožňuje vložit volání jiného výpočetního výrazu a provést porovnání vzorů na jeho výsledku.
let doThingsAsync url =
async {
match! callService url with
| Some data -> ...
| None -> ...
}
Při volání výpočetního výrazu s match!, zjistí výsledek volání jako let!. Často se používá při volání výpočetního výrazu, kde je výsledek nepovinný.
Předdefinované výpočetní výrazy
Základní knihovna jazyka F# definuje čtyři předdefinované výpočetní výrazy: sequence Expressions, Async expressions, Task expressions a Query Expressions.
Vytvoření nového typu výpočetního výrazu
Vlastnosti vlastních výpočetních výrazů můžete definovat vytvořením třídy tvůrce a definováním určitých speciálních metod třídy. Třída tvůrce může volitelně definovat metody uvedené v následující tabulce.
Následující tabulka popisuje metody, které lze použít ve třídě tvůrce pracovních postupů.
| Metoda | Typické podpisy | Popis |
|---|---|---|
Bind |
M<'T> * ('T -> M<'U>) -> M<'U> |
Vyžadováno pro let! a do! ve výpočetních výrazech. |
BindN |
(M<'T1> * M<'T2> * ... * M<'TN> * ('T1 * 'T2 ... * 'TN -> M<'U>)) -> M<'U> |
Bylo požadováno efektivní let! a and! u výpočetních výrazů bez sloučení vstupů.například Bind3, Bind4. |
Delay |
(unit -> M<'T>) -> Delayed<'T> |
Zabalí výpočetní výraz do funkce.
Delayed<'T> může být libovolný typ, běžně M<'T> nebo unit -> M<'T> se používá. Výchozí implementace vrátí M<'T>hodnotu . |
Return |
'T -> M<'T> |
return Volá se ve výpočetních výrazech. |
ReturnFrom |
M<'T> -> M<'T> |
return! Volá se ve výpočetních výrazech. |
ReturnFromFinal |
M<'T> -> M<'T> |
Pokud je k dispozici, volal a return!do! kdy v pozici koncového volání. |
BindReturn |
(M<'T1> * ('T1 -> 'T2)) -> M<'T2> |
Bylo požadováno efektivní let! ... return ve výpočetních výrazech. |
BindNReturn |
(M<'T1> * M<'T2> * ... * M<'TN> * ('T1 * 'T2 ... * 'TN -> M<'U>)) -> M<'U> |
Požadovali jsme efektivní let! ... and! ... return ve výpočetních výrazech bez slučování vstupů.například Bind3Return, Bind4Return. |
MergeSources |
(M<'T1> * M<'T2>) -> M<'T1 * 'T2> |
and! Volá se ve výpočetních výrazech. |
MergeSourcesN |
(M<'T1> * M<'T2> * ... * M<'TN>) -> M<'T1 * 'T2 * ... * 'TN> |
Požadováno pro and! ve výpočetních výrazech, ale zlepšuje efektivitu snížením počtu uzlů vytváření dvojic.například MergeSources3, MergeSources4. |
Run |
Delayed<'T> -> M<'T> neboM<'T> -> 'T |
Spustí výpočetní výraz. |
Combine |
M<'T> * Delayed<'T> -> M<'T> neboM<unit> * M<'T> -> M<'T> |
Sekvencování se volá ve výpočetních výrazech. |
For |
seq<'T> * ('T -> M<'U>) -> M<'U> neboseq<'T> * ('T -> M<'U>) -> seq<M<'U>> |
Volá se pro for...do výrazy ve výpočetních výrazech. |
TryFinally |
Delayed<'T> * (unit -> unit) -> M<'T> |
Volá se pro try...finally výrazy ve výpočetních výrazech. |
TryWith |
Delayed<'T> * (exn -> M<'T>) -> M<'T> |
Volá se pro try...with výrazy ve výpočetních výrazech. |
Using |
'T * ('T -> M<'U>) -> M<'U> when 'T :> IDisposable |
Byly vyžádány vazby use ve výpočetních výrazech. |
While |
(unit -> bool) * Delayed<'T> -> M<'T>nebo(unit -> bool) * Delayed<unit> -> M<unit> |
Volá se pro while...do výrazy ve výpočetních výrazech. |
Yield |
'T -> M<'T> |
Volá se pro yield výrazy ve výpočetních výrazech. |
YieldFrom |
M<'T> -> M<'T> |
Volá se pro yield! výrazy ve výpočetních výrazech. |
YieldFromFinal |
M<'T> -> M<'T> |
Pokud je k dispozici, volá se yield! při pozici koncového volání a v případě pozice koncového do! volání jako záložní pozice pro ReturnFromFinal |
Zero |
unit -> M<'T> |
Volá se pro prázdné else větve výrazů if...then ve výpočetních výrazech. |
Quote |
Quotations.Expr<'T> -> Quotations.Expr<'T> |
Označuje, že výpočetní výraz je předán členu Run jako citace. Převede všechny instance výpočtu do citace. |
Mnoho metod ve stavitelné třídě používá a vrací M<'T> konstrukci, což je obvykle samostatně definovaný typ, který charakterizuje typ kombinovaných výpočtů, například Async<'T> pro asynchronní výrazy a Seq<'T> pro sekvenční pracovní postupy. Podpisy těchto metod umožňují jejich kombinování a vnoření mezi sebou, aby objekt pracovního postupu vrácený z jedné konstrukce mohl být předán do další.
Mnoho funkcí používá výsledek Delay jako argument: Run, While, TryWith, TryFinally, a Combine. Typ Delayed<'T> je návratový typ Delay a tedy také parametr pro tyto funkce.
Delayed<'T> může být libovolný typ, který nemusí souviset s M<'T>; běžně M<'T> nebo (unit -> M<'T>) se používají. Výchozí implementace je M<'T>. Podrobnější pohled najdete v tématu Vysvětlení omezení typu.
Kompilátor při analýze výpočetního výrazu přeloží výraz do řady vnořených volání funkcí pomocí metod v předchozí tabulce a kódu ve výpočetním výrazu. Vnořený výraz má následující tvar:
builder.Run(builder.Delay(fun () -> {{ cexpr }}))
Ve výše uvedeném kódu jsou volání Run a Delay vynechána, pokud nejsou definována ve třídě tvůrce výpočetních výrazů. Tělo výpočetního výrazu, zde označeno jako {{ cexpr }}, je přeloženo do dalších volání metod třídy sestavovatele. Tento proces je definován rekurzivně podle překladů v následující tabulce. Kód v dvojitých závorkách {{ ... }} zůstane přeložen, expr představuje výraz jazyka F# a cexpr představuje výpočetní výraz.
| Výraz | Překlad |
|---|---|
{{ let binding in cexpr }} |
let binding in {{ cexpr }} |
{{ let! pattern = expr in cexpr }} |
builder.Bind(expr, (fun pattern -> {{ cexpr }})) |
{{ do! expr in cexpr }} |
builder.Bind(expr, (fun () -> {{ cexpr }})) |
{{ yield expr }} |
builder.Yield(expr) |
{{ yield! expr }} |
builder.YieldFrom(expr) |
{{ return expr }} |
builder.Return(expr) |
{{ return! expr }} |
builder.ReturnFrom(expr) |
{{ use pattern = expr in cexpr }} |
builder.Using(expr, (fun pattern -> {{ cexpr }})) |
{{ use! value = expr in cexpr }} |
builder.Bind(expr, (fun value -> builder.Using(value, (fun value -> {{ cexpr }})))) |
{{ if expr then cexpr0 }} |
if expr then {{ cexpr0 }} else builder.Zero() |
{{ if expr then cexpr0 else cexpr1 }} |
if expr then {{ cexpr0 }} else {{ cexpr1 }} |
{{ match expr with | pattern_i -> cexpr_i }} |
match expr with | pattern_i -> {{ cexpr_i }} |
{{ for pattern in enumerable-expr do cexpr }} |
builder.For(enumerable-expr, (fun pattern -> {{ cexpr }})) |
{{ for identifier = expr1 to expr2 do cexpr }} |
builder.For([expr1..expr2], (fun identifier -> {{ cexpr }})) |
{{ while expr do cexpr }} |
builder.While(fun () -> expr, builder.Delay({{ cexpr }})) |
{{ try cexpr with | pattern_i -> expr_i }} |
builder.TryWith(builder.Delay({{ cexpr }}), (fun value -> match value with | pattern_i -> expr_i | exn -> System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exn).Throw())) |
{{ try cexpr finally expr }} |
builder.TryFinally(builder.Delay({{ cexpr }}), (fun () -> expr)) |
{{ cexpr1; cexpr2 }} |
builder.Combine({{ cexpr1 }}, {{ cexpr2 }}) |
{{ other-expr; cexpr }} |
expr; {{ cexpr }} |
{{ other-expr }} |
expr; builder.Zero() |
V předchozí tabulce popisuje výraz, other-expr který není jinak uveden v tabulce. Třída tvůrce nemusí implementovat všechny metody a podporovat všechny překlady uvedené v předchozí tabulce. Tyto konstrukce, které nejsou implementovány, nejsou k dispozici ve výpočetních výrazech daného typu. Pokud například nechcete podporovat klíčové slovo use ve výpočetních výrazech, můžete vynechat definici Use ve třídě konstruktéru.
Následující příklad kódu ukazuje výpočetní výraz, který zapouzdřuje výpočet do série kroků, jež lze vyhodnocovat postupně po jednotlivých krocích. Diskriminovaný sjednocovací typ OkOrException, kóduje stav chyby výrazu, jak je dosud vyhodnoceno. Tento kód ukazuje několik typických vzorů, které můžete použít ve výpočetních výrazech, jako jsou standardní implementace některých metod tvůrce.
/// Represents computations that can be run step by step
type Eventually<'T> =
| Done of 'T
| NotYetDone of (unit -> Eventually<'T>)
module Eventually =
/// Bind a computation using 'func'.
let rec bind func expr =
match expr with
| Done value -> func value
| NotYetDone work -> NotYetDone (fun () -> bind func (work()))
/// Return the final value
let result value = Done value
/// The catch for the computations. Stitch try/with throughout
/// the computation, and return the overall result as an OkOrException.
let rec catch expr =
match expr with
| Done value -> result (Ok value)
| NotYetDone work ->
NotYetDone (fun () ->
let res = try Ok(work()) with | exn -> Error exn
match res with
| Ok cont -> catch cont // note, a tailcall
| Error exn -> result (Error exn))
/// The delay operator.
let delay func = NotYetDone (fun () -> func())
/// The stepping action for the computations.
let step expr =
match expr with
| Done _ -> expr
| NotYetDone func -> func ()
/// The tryFinally operator.
/// This is boilerplate in terms of "result", "catch", and "bind".
let tryFinally expr compensation =
catch (expr)
|> bind (fun res ->
compensation();
match res with
| Ok value -> result value
| Error exn -> raise exn)
/// The tryWith operator.
/// This is boilerplate in terms of "result", "catch", and "bind".
let tryWith exn handler =
catch exn
|> bind (function Ok value -> result value | Error exn -> handler exn)
/// The whileLoop operator.
/// This is boilerplate in terms of "result" and "bind".
let rec whileLoop pred body =
if pred() then body |> bind (fun _ -> whileLoop pred body)
else result ()
/// The sequential composition operator.
/// This is boilerplate in terms of "result" and "bind".
let combine expr1 expr2 =
expr1 |> bind (fun () -> expr2)
/// The using operator.
/// This is boilerplate in terms of "tryFinally" and "Dispose".
let using (resource: #System.IDisposable) func =
tryFinally (func resource) (fun () -> resource.Dispose())
/// The forLoop operator.
/// This is boilerplate in terms of "catch", "result", and "bind".
let forLoop (collection:seq<_>) func =
let ie = collection.GetEnumerator()
tryFinally
(whileLoop
(fun () -> ie.MoveNext())
(delay (fun () -> let value = ie.Current in func value)))
(fun () -> ie.Dispose())
/// The builder class.
type EventuallyBuilder() =
member x.Bind(comp, func) = Eventually.bind func comp
member x.Return(value) = Eventually.result value
member x.ReturnFrom(value) = value
member x.Combine(expr1, expr2) = Eventually.combine expr1 expr2
member x.Delay(func) = Eventually.delay func
member x.Zero() = Eventually.result ()
member x.TryWith(expr, handler) = Eventually.tryWith expr handler
member x.TryFinally(expr, compensation) = Eventually.tryFinally expr compensation
member x.For(coll:seq<_>, func) = Eventually.forLoop coll func
member x.Using(resource, expr) = Eventually.using resource expr
let eventually = new EventuallyBuilder()
let comp =
eventually {
for x in 1..2 do
printfn $" x = %d{x}"
return 3 + 4
}
/// Try the remaining lines in F# interactive to see how this
/// computation expression works in practice.
let step x = Eventually.step x
// returns "NotYetDone <closure>"
comp |> step
// prints "x = 1"
// returns "NotYetDone <closure>"
comp |> step |> step
// prints "x = 1"
// prints "x = 2"
// returns "Done 7"
comp |> step |> step |> step |> step
Výpočetní výraz má základní typ, který výraz vrátí. Základní typ může představovat vypočítaný výsledek nebo zpožděný výpočet, který lze provést, nebo může poskytnout způsob, jak iterovat nějakým typem kolekce. V předchozím příkladu byl Eventually<_>základní typ . U sekvenčního výrazu je System.Collections.Generic.IEnumerable<T>podkladový typ . U výrazu dotazu je System.Linq.IQueryablepodkladový typ . Pro asynchronní výraz je Asyncpodkladový typ . Objekt Async představuje práci, která se má provést pro výpočet výsledku. Například zavoláte Async.RunSynchronously, abyste provedli výpočet a vrátili výsledek.
Vlastní operace
Můžete definovat vlastní operaci pro výpočetní výraz a použít vlastní operaci jako operátor ve výpočetním výrazu. Do výrazu dotazu můžete například zahrnout operátor dotazu. Když definujete vlastní operaci, musíte definovat metody Yield a For ve výpočetním výrazu. Chcete-li definovat vlastní operaci, vložte ji do třídy tvůrce pro výpočetní výraz a pak použijte CustomOperationAttribute. Tento atribut přebírá řetězec jako argument, což je název, který se má použít ve vlastní operaci. Tento název vstupuje do rozsahu na začátku otevírací složené závorky výpočetního výrazu. Proto byste neměli používat identifikátory, které mají stejný název jako vlastní operace v tomto bloku. Vyhněte se například použití identifikátorů, jako jsou all nebo last ve výrazech dotazu.
Rozšíření existujících builderů o nové vlastní operace
Pokud již máte třídu tvůrce, její vlastní operace lze rozšířit mimo tuto třídu tvůrce. Rozšíření musí být deklarována v modulech. Jmenné prostory nemohou obsahovat členy rozšíření, s výjimkou případů, kdy se nachází ve stejném souboru a ve stejné deklaraci jmenného prostoru, kde je typ definován.
Následující příklad ukazuje rozšíření existující FSharp.Linq.QueryBuilder třídy.
open System
open FSharp.Linq
type QueryBuilder with
[<CustomOperation>]
member _.any (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate))
[<CustomOperation("singleSafe")>] // you can specify your own operation name in the constructor
member _.singleOrDefault (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.SingleOrDefault (source.Source, Func<_,_>(predicate))
Vlastní operace je možné přetížit. Další informace najdete v tématu F# RFC FS-1056 – Povolení přetížení vlastních klíčových slov ve výpočetních výrazech.
Efektivní kompilace výpočetních výrazů
Výpočetní výrazy jazyka F#, které pozastaví provádění, je možné zkompilovat do vysoce efektivních stavových počítačů pomocí pečlivého použití funkce nízké úrovně označované jako obnovitelný kód. Obnovitelný kód je zdokumentovaný v F# RFC FS-1087 a používá se pro výrazy úloh.
Výpočetní výrazy jazyka F#, které jsou synchronní (tj. nepřestavují provádění), lze alternativně zkompilovat do efektivních stavových počítačů pomocí vložených funkcí včetně atributu InlineIfLambda . Příklady jsou uvedeny v F# RFC FS-1098.
Výrazy seznamů, výrazy pole a sekvenční výrazy mají speciální zacházení kompilátorem jazyka F#, aby se zajistilo generování vysoce výkonného kódu.