open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
// Quotations: code as data (typed ASTs)
let expr: Expr<int> = <@ 1 + 2 * 3 @>
let untyped = <@@ fun x -> x + 1 @@>
let rec describe (e: Expr) =
match e with
| Value (v, _) -> string v
| Call (_, mi, [ a; b ]) -> $"({describe a} {mi.Name} {describe b})"
| Lambda (v, body) -> $"fun {v.Name} -> {describe body}"
| Var v -> v.Name
| _ -> "?"
describe expr // e.g. "(1 op_Addition (2 op_Multiply 3))"
// Evaluate quotations with FSharp.Quotations.Evaluator or LINQ expression conversion
// Quotations power: Fable (historically), query translation (SQL), GPU compilers, test assertions (Unquote: test <@ x = 2 @>)
// [<ReflectedDefinition>] keeps a function's quotation available at runtime
[<ReflectedDefinition>]
let square x = x * x
// Reflection
open Microsoft.FSharp.Reflection
type Shape = Circle of float | Square of float
FSharpType.GetUnionCases typeof<Shape> |> Array.map _.Name // [|"Circle"; "Square"|]
let case, fields = FSharpValue.GetUnionFields(Circle 2.0, typeof<Shape>)
type Pt = { X: int; Y: int }
FSharpType.GetRecordFields typeof<Pt> |> Array.map _.Name // [|"X"
…