3 people like it.

Normalization by Evaluation

Optimizing F# quotations by applying Normalization-by-Evaluation

Implementation

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
open System
open System.Reflection
open FSharp.Reflection
open FSharp.Quotations
open FSharp.Quotations.Patterns
open FSharp.Quotations.DerivedPatterns
open FSharp.Quotations.ExprShape

// Semantic interpretation of quotation trees
type Sem =
    | VAR of Var * value:Sem option
    | LIT of obj * Type
    | LAM of Var * (Sem -> Sem)
    | LET of Var * Sem * Sem
    | TUPLE of Type * Sem list
    | RECORD of Type * Sem list
    | UNION of UnionCaseInfo * Sem list
    // Standard arithmetic operator expression
    | OP of MethodInfo * Sem list
    // Embeds arbitrary syntactic trees
    | SYN of isPureNode:bool * shape:obj * Sem list

/// determines if expression is guaranteed to evaluate without side-effects
let rec isPure (s : Sem) =
    match s with
    | VAR (v,_) -> not v.IsMutable
    | LIT _ | LAM _ -> true
    | SYN(isPureNode = isPure) -> isPure
    | LET(_,b,k) -> isPure b && isPure k
    | TUPLE (_,fs) | RECORD (_,fs) | UNION(_,fs) | OP(_,fs) -> fs |> List.forall isPure

type Environment = Map<Var, Sem>

/// Maps syntactic trees to semantic expressions; apply optimizations as required
let rec meaning (env : Environment) (expr : Expr) : Sem =
    let mkLit (x : 'T) = LIT(x, typeof<'T>)

    let (|Deref|) s =
        match s with
        | VAR(_, Some s) -> s
        | _ -> s

    // trivial semantic mapping; use as fallback when no other optimizations can be applied
    let fallback (env : Environment) (expr : Expr) =
        match expr with
        | ShapeVar v -> 
            match env.TryFind v with
            | Some (LIT _ | VAR _ as s) -> s
            | sopt -> VAR(v, sopt)
        | ShapeLambda(v, body) -> LAM(v, fun s -> meaning (env.Add(v, s)) body)
        | ShapeCombination(shape, args) ->
            let sargs = args |> List.map (meaning env)
            let isPureNode =
                match expr with
                | IfThenElse _
                | TupleGet _
                | TypeTest _
                | UnionCaseTest _
                | LetRecursive _
                | QuoteRaw _
                | QuoteTyped _ -> true
                | PropertyGet(Some e, _, []) when 
                    FSharpType.IsRecord(e.Type, true) || 
                    FSharpType.IsUnion(e.Type, true) ||
                    FSharpType.IsTuple(e.Type) -> true
                | _ -> false

            SYN(isPureNode, shape, sargs)
        
    match expr with
    | Value(o, t) -> LIT(o, t)
    | Application(f, g) ->
        match meaning env f with
        | Deref (LAM (v, lam)) ->
            match meaning env g with
            // (λ x. M) N ~> M[N/x]
            | LIT _ | VAR _ | LAM _ as s -> lam s
            // (λ x. M) N ~> let x = N in M
            | s -> LET(v, s, lam (VAR(v, Some s)))
        | _ -> fallback env expr

    | Let(v, binding, body) when not v.IsMutable ->
        let (Deref s) = meaning env binding
        match meaning (env.Add(v, s)) body with
        | VAR(x, _) when x = v -> s // let x = N in x ~> N
        | sk -> LET(v, s, sk)

    | IfThenElse(cond, ifExpr, elseExpr) ->
        match meaning env cond with
        | Deref (LIT(:? bool as ccond, _)) ->
            // branch elimination
            let branch = if ccond then ifExpr else elseExpr
            meaning env branch
        | _ -> fallback env expr

    | Sequential(left, right) ->
        match meaning env left with
        | ls when isPure ls -> 
            match meaning env right with
            | rs when isPure rs -> mkLit ()
            | rs -> rs
        | _ -> fallback env expr

    // Tuple introduction & elimination [https://github.com/dotnet/fsharp/issues/7914]
    | NewTuple ts when not expr.Type.IsValueType -> TUPLE(expr.Type, ts |> List.map (meaning env))
    | TupleGet(tuple, i) ->
        match meaning env tuple with
        | Deref (TUPLE (_, ts)) -> ts.[i]
        | _ -> fallback env expr

    // Record introduction & elimination
    | NewRecord(t, fs) -> RECORD(t, fs |> List.map (meaning env))
    | PropertyGet(Some e, prop, []) ->
        match meaning env e with
        | Deref (RECORD(t,fs)) -> 
            match FSharpType.GetRecordFields(t, true) |> Array.tryFindIndex(fun p -> prop = p) with
            | Some i -> fs.[i]
            | None -> fallback env expr
        | Deref (UNION(uci, fs)) ->
            match uci.GetFields() |> Array.tryFindIndex(fun p -> prop = p) with
            | Some i -> fs.[i]
            | None -> fallback env expr
        | _ -> fallback env expr

    // Union introduction & elimination
    | NewUnionCase(uci, fs) -> UNION(uci, fs |> List.map (meaning env))
    | UnionCaseTest(e, uci) ->
        match meaning env e with
        | Deref (UNION(uci', _)) -> mkLit(uci = uci')
        | _ -> fallback env expr

    | SpecificCall <@ (|>) @> (None, _, [value; func])
    | SpecificCall <@ (<|) @> (None, _, [func; value]) -> meaning env (Expr.Application(func, value))

    | SpecificCall <@ fst @> (None, _, [t]) -> meaning env (Expr.TupleGet(t, 0))
    | SpecificCall <@ snd @> (None, _, [t]) -> meaning env (Expr.TupleGet(t, 1))
    | SpecificCall <@ ignore @> (None, _, [value]) -> meaning env (Expr.Sequential(value, Expr.Value(())))

    | Call(None, mi, args) when mi.DeclaringType.FullName = "Microsoft.FSharp.Core.Operators" && mi.Name.StartsWith "op_" ->
        let sargs = args |> List.map (meaning env)
        let literals = sargs |> Seq.choose (function (Deref (LIT(o,_))) -> Some o | _ -> None) |> Seq.toArray
        if literals.Length = sargs.Length then
            // evaluate constant expressions
            try LIT(mi.Invoke(null, literals), expr.Type)
            with :? TargetException as e when (e.InnerException :? NotSupportedException) ->
                // "Dynamic invocation of operator is not supported"
                OP(mi, sargs)
        else
            OP(mi, sargs)

    | _ -> fallback env expr

/// Maps semantic expressions back to a syntactic representation
let reify (s : Sem) : Expr =
    let rec aux (refdVars : Set<Var>) s =
        let foldMap refdVars (ss : Sem list) =
            let mutable refdVars = refdVars
            let es = ss |> List.map (fun s -> let r,e = aux refdVars s in refdVars <- r; e)
            refdVars, es

        match s with
        | VAR (v, _) -> refdVars.Add v, Expr.Var v
        | LIT (o, t) -> refdVars, Expr.Value(o, t)
        | LAM (v, lam) -> refdVars, Expr.Lambda(v, lam (VAR (v, None)) |> aux refdVars |> snd)
        | LET (v, b, k) ->
            let kvars, ek = aux refdVars k
            if isPure b && not (kvars.Contains v) then
                kvars, ek
            else 
                let bvars, eb = aux refdVars b
                Set.union kvars bvars, Expr.Let(v, eb, ek)

        | TUPLE (_,fs) -> let refdVars,es = foldMap refdVars fs in refdVars, Expr.NewTuple(es)
        | RECORD (t, fs) -> let refdVars,es = foldMap refdVars fs in refdVars, Expr.NewRecord(t, es)
        | UNION (uci, fs) -> let refdVars,es = foldMap refdVars fs in refdVars, Expr.NewUnionCase(uci, es)
        | OP(mI, args) -> let refdVars,es = foldMap refdVars args in refdVars, Expr.Call(mI, es)
        | SYN(_, shape, sparams) -> let refdVars,es = foldMap refdVars sparams in refdVars, RebuildShapeCombination(shape, es)

    aux Set.empty s |> snd

/// Apply normalization-by-evaluation to quotation tree
let nbe (expr : Expr<'a>) : Expr<'a> = expr |> meaning Map.empty |> reify |> Expr.Cast

Examples

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
let nbe_decompile expr = expr |> nbe |> Swensen.Unquote.Operators.decompile

nbe_decompile 
    <@
        let f x =
            match x with
            | Some i -> i > 0
            | None -> false

        f (Some 42), f None
    @>
// (true, false)

nbe_decompile 
    <@ 
        fun () -> 
            let mutable y = 0
            let f x = x + 2
            y <- f 2
            y + 1
    @>
// fun () -> let mutable y = 0 in y <- 4; y + 1

nbe_decompile 
    <@
        fun z ->
            let f x =
                if x > 0 then Console.WriteLine "Positive"
                elif x = 0 then Console.WriteLine "Zero"
                else Console.WriteLine "Negative"

            f -1; f 0; f z
    @>
// fun z -> 
//      Console.WriteLine("Negative")
//      Console.WriteLine("Zero")
//      if z > 0 then Console.WriteLine("Positive") 
//      else (if z = 0 then Console.WriteLine("Zero")
//      else Console.WriteLine("Negative"))

Stream pipelines

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
// Nessos streams: http://trelford.com/blog/post/SeqVsStream.aspx
type Stream<'T> = ('T -> unit) -> unit

nbe_decompile
    <@
        let ofArray (xs : int []) =
            fun k -> for x in xs do k x

        let map : (int -> int) -> Stream<int> -> Stream<int> =
            fun f ts k -> ts (fun t -> k (f t))

        let filter : (int -> bool) -> Stream<int> -> Stream<int> =
            fun f ts k -> ts (fun t -> if (f t) then k t)

        let iter : (int -> unit) -> Stream<int> -> unit =
            fun f ts -> ts f

        fun xs ->
            ofArray xs
            |> filter (fun i -> i > 0)
            |> filter (fun i -> i % 2 = 0)
            |> map (fun i -> i * i)
            |> map (fun i -> i + i)
            |> iter (fun i -> printfn "%d" i)
    @>

//fun (xs : int []) ->
//    for x in xs do
//        if x > 0 then
//            if x % 2 = 0 then
//                let t = x * x
//                let i = t + t
//                printfn "%d" i
namespace System
namespace System.Reflection
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
namespace Microsoft.FSharp.Quotations
module Patterns

from Microsoft.FSharp.Quotations
module DerivedPatterns

from Microsoft.FSharp.Quotations
module ExprShape

from Microsoft.FSharp.Quotations
type Sem =
  | VAR of Var * value: Sem option
  | LIT of obj * Type
  | LAM of Var * (Sem -> Sem)
  | LET of Var * Sem * Sem
  | TUPLE of Type * Sem list
  | RECORD of Type * Sem list
  | UNION of UnionCaseInfo * Sem list
  | OP of MethodInfo * Sem list
  | SYN of isPureNode: bool * shape: obj * Sem list

Full name: Script.Sem
union case Sem.VAR: Var * value: Sem option -> Sem
Multiple items
active recognizer Var: Expr -> Var option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Var|_| )

--------------------
type Var =
  interface IComparable
  new : name:string * typ:Type * ?isMutable:bool -> Var
  member IsMutable : bool
  member Name : string
  member Type : Type
  static member Global : name:string * typ:Type -> Var

Full name: Microsoft.FSharp.Quotations.Var

--------------------
new : name:string * typ:Type * ?isMutable:bool -> Var
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
union case Sem.LIT: obj * Type -> Sem
type obj = Object

Full name: Microsoft.FSharp.Core.obj
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
union case Sem.LAM: Var * (Sem -> Sem) -> Sem
union case Sem.LET: Var * Sem * Sem -> Sem
union case Sem.TUPLE: Type * Sem list -> Sem
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
union case Sem.RECORD: Type * Sem list -> Sem
union case Sem.UNION: UnionCaseInfo * Sem list -> Sem
type UnionCaseInfo
member GetCustomAttributes : unit -> obj []
member GetCustomAttributes : attributeType:Type -> obj []
member GetCustomAttributesData : unit -> IList<CustomAttributeData>
member GetFields : unit -> PropertyInfo []
member DeclaringType : Type
member Name : string
member Tag : int

Full name: Microsoft.FSharp.Reflection.UnionCaseInfo
union case Sem.OP: MethodInfo * Sem list -> Sem
type MethodInfo =
  inherit MethodBase
  member Equals : obj:obj -> bool
  member GetBaseDefinition : unit -> MethodInfo
  member GetGenericArguments : unit -> Type[]
  member GetGenericMethodDefinition : unit -> MethodInfo
  member GetHashCode : unit -> int
  member MakeGenericMethod : [<ParamArray>] typeArguments:Type[] -> MethodInfo
  member MemberType : MemberTypes
  member ReturnParameter : ParameterInfo
  member ReturnType : Type
  member ReturnTypeCustomAttributes : ICustomAttributeProvider

Full name: System.Reflection.MethodInfo
union case Sem.SYN: isPureNode: bool * shape: obj * Sem list -> Sem
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
val isPure : s:Sem -> bool

Full name: Script.isPure


 determines if expression is guaranteed to evaluate without side-effects
val s : Sem
val v : Var
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
property Var.IsMutable: bool
val isPure : bool
val b : Sem
val k : Sem
val fs : Sem list
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val forall : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.forall
type Environment = Map<Var,Sem>

Full name: Script.Environment
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val meaning : env:Environment -> expr:Expr -> Sem

Full name: Script.meaning


 Maps syntactic trees to semantic expressions; apply optimizations as required
val env : Environment
val expr : Expr
Multiple items
type Expr =
  override Equals : obj:obj -> bool
  member GetFreeVars : unit -> seq<Var>
  member Substitute : substitution:(Var -> Expr option) -> Expr
  member ToString : full:bool -> string
  member CustomAttributes : Expr list
  member Type : Type
  static member AddressOf : target:Expr -> Expr
  static member AddressSet : target:Expr * value:Expr -> Expr
  static member Application : functionExpr:Expr * argument:Expr -> Expr
  static member Applications : functionExpr:Expr * arguments:Expr list list -> Expr
  ...

Full name: Microsoft.FSharp.Quotations.Expr

--------------------
type Expr<'T> =
  inherit Expr
  member Raw : Expr

Full name: Microsoft.FSharp.Quotations.Expr<_>
val mkLit : ('T -> Sem)
val x : 'T
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
union case Option.Some: Value: 'T -> Option<'T>
val fallback : (Environment -> Expr -> Sem)
active recognizer ShapeVar: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>

Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
member Map.TryFind : key:'Key -> 'Value option
val sopt : Sem option
active recognizer ShapeLambda: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>

Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
val body : Expr
member Map.Add : key:'Key * value:'Value -> Map<'Key,'Value>
active recognizer ShapeCombination: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>

Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
val shape : obj
val args : Expr list
val sargs : Sem list
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val isPureNode : bool
active recognizer IfThenElse: Expr -> (Expr * Expr * Expr) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |IfThenElse|_| )
active recognizer TupleGet: Expr -> (Expr * int) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |TupleGet|_| )
active recognizer TypeTest: Expr -> (Expr * Type) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |TypeTest|_| )
active recognizer UnionCaseTest: Expr -> (Expr * UnionCaseInfo) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |UnionCaseTest|_| )
active recognizer LetRecursive: Expr -> ((Var * Expr) list * Expr) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |LetRecursive|_| )
active recognizer QuoteRaw: Expr -> Expr option

Full name: Microsoft.FSharp.Quotations.Patterns.( |QuoteRaw|_| )
active recognizer QuoteTyped: Expr -> Expr option

Full name: Microsoft.FSharp.Quotations.Patterns.( |QuoteTyped|_| )
active recognizer PropertyGet: Expr -> (Expr option * PropertyInfo * Expr list) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |PropertyGet|_| )
val e : Expr
type FSharpType =
  static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetFunctionElements : functionType:Type -> Type * Type
  static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetTupleElements : tupleType:Type -> Type []
  static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
  static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
  static member IsFunction : typ:Type -> bool
  static member IsModule : typ:Type -> bool
  static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
  static member IsTuple : typ:Type -> bool
  ...

Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.IsRecord : typ:Type * ?allowAccessToPrivateRepresentation:bool -> bool
static member FSharpType.IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
property Expr.Type: Type
static member FSharpType.IsUnion : typ:Type * ?allowAccessToPrivateRepresentation:bool -> bool
static member FSharpType.IsUnion : typ:Type * ?bindingFlags:BindingFlags -> bool
static member FSharpType.IsTuple : typ:Type -> bool
active recognizer Value: Expr -> (obj * Type) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Value|_| )
val o : obj
val t : Type
active recognizer Application: Expr -> (Expr * Expr) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Application|_| )
val f : Expr
val g : Expr
active recognizer Deref: Sem -> Sem
val lam : (Sem -> Sem)
active recognizer Let: Expr -> (Var * Expr * Expr) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Let|_| )
val binding : Expr
val x : Var
val sk : Sem
val cond : Expr
val ifExpr : Expr
val elseExpr : Expr
val ccond : bool
val branch : Expr
active recognizer Sequential: Expr -> (Expr * Expr) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Sequential|_| )
val left : Expr
val right : Expr
val ls : Sem
val rs : Sem
active recognizer NewTuple: Expr -> Expr list option

Full name: Microsoft.FSharp.Quotations.Patterns.( |NewTuple|_| )
val ts : Expr list
property Type.IsValueType: bool
val tuple : Expr
val i : int
val ts : Sem list
active recognizer NewRecord: Expr -> (Type * Expr list) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |NewRecord|_| )
val fs : Expr list
val prop : PropertyInfo
static member FSharpType.GetRecordFields : recordType:Type * ?allowAccessToPrivateRepresentation:bool -> PropertyInfo []
static member FSharpType.GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val tryFindIndex : predicate:('T -> bool) -> array:'T [] -> int option

Full name: Microsoft.FSharp.Collections.Array.tryFindIndex
val p : PropertyInfo
union case Option.None: Option<'T>
val uci : UnionCaseInfo
member UnionCaseInfo.GetFields : unit -> PropertyInfo []
active recognizer NewUnionCase: Expr -> (UnionCaseInfo * Expr list) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |NewUnionCase|_| )
val uci' : UnionCaseInfo
active recognizer SpecificCall: Expr -> Expr -> (Expr option * Type list * Expr list) option

Full name: Microsoft.FSharp.Quotations.DerivedPatterns.( |SpecificCall|_| )
val value : Expr
val func : Expr
static member Expr.Application : functionExpr:Expr * argument:Expr -> Expr
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val t : Expr
static member Expr.TupleGet : tuple:Expr * index:int -> Expr
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
static member Expr.Sequential : first:Expr * second:Expr -> Expr
static member Expr.Value : value:'T -> Expr
static member Expr.Value : value:obj * expressionType:Type -> Expr
active recognizer Call: Expr -> (Expr option * MethodInfo * Expr list) option

Full name: Microsoft.FSharp.Quotations.Patterns.( |Call|_| )
val mi : MethodInfo
property MemberInfo.DeclaringType: Type
property Type.FullName: string
property MemberInfo.Name: string
String.StartsWith(value: string) : bool
String.StartsWith(value: string, comparisonType: StringComparison) : bool
String.StartsWith(value: string, ignoreCase: bool, culture: Globalization.CultureInfo) : bool
val literals : obj []
module Seq

from Microsoft.FSharp.Collections
val choose : chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.choose
val toArray : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Seq.toArray
property Array.Length: int
property List.Length: int
MethodBase.Invoke(obj: obj, parameters: obj []) : obj
MethodBase.Invoke(obj: obj, invokeAttr: BindingFlags, binder: Binder, parameters: obj [], culture: Globalization.CultureInfo) : obj
Multiple items
type TargetException =
  inherit ApplicationException
  new : unit -> TargetException + 2 overloads

Full name: System.Reflection.TargetException

--------------------
TargetException() : unit
TargetException(message: string) : unit
TargetException(message: string, inner: exn) : unit
val e : TargetException
property Exception.InnerException: exn
Multiple items
type NotSupportedException =
  inherit SystemException
  new : unit -> NotSupportedException + 2 overloads

Full name: System.NotSupportedException

--------------------
NotSupportedException() : unit
NotSupportedException(message: string) : unit
NotSupportedException(message: string, innerException: exn) : unit
val reify : s:Sem -> Expr

Full name: Script.reify


 Maps semantic expressions back to a syntactic representation
val aux : (Set<Var> -> Sem -> Set<Var> * Expr)
val refdVars : Set<Var>
Multiple items
module Set

from Microsoft.FSharp.Collections

--------------------
type Set<'T (requires comparison)> =
  interface IComparable
  interface IEnumerable
  interface IEnumerable<'T>
  interface ICollection<'T>
  new : elements:seq<'T> -> Set<'T>
  member Add : value:'T -> Set<'T>
  member Contains : value:'T -> bool
  override Equals : obj -> bool
  member IsProperSubsetOf : otherSet:Set<'T> -> bool
  member IsProperSupersetOf : otherSet:Set<'T> -> bool
  ...

Full name: Microsoft.FSharp.Collections.Set<_>

--------------------
new : elements:seq<'T> -> Set<'T>
val foldMap : (Set<Var> -> Sem list -> Set<Var> * Expr list)
val ss : Sem list
val mutable refdVars : Set<Var>
val es : Expr list
val r : Set<Var>
member Set.Add : value:'T -> Set<'T>
static member Expr.Var : variable:Var -> Expr
static member Expr.Lambda : parameter:Var * body:Expr -> Expr
val kvars : Set<Var>
val ek : Expr
member Set.Contains : value:'T -> bool
val bvars : Set<Var>
val eb : Expr
val union : set1:Set<'T> -> set2:Set<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.union
static member Expr.Let : letVariable:Var * letExpr:Expr * body:Expr -> Expr
static member Expr.NewTuple : elements:Expr list -> Expr
static member Expr.NewRecord : recordType:Type * elements:Expr list -> Expr
static member Expr.NewUnionCase : unionCase:UnionCaseInfo * arguments:Expr list -> Expr
val mI : MethodInfo
val args : Sem list
static member Expr.Call : methodInfo:MethodInfo * arguments:Expr list -> Expr
static member Expr.Call : obj:Expr * methodInfo:MethodInfo * arguments:Expr list -> Expr
val sparams : Sem list
val RebuildShapeCombination : shape:obj * arguments:Expr list -> Expr

Full name: Microsoft.FSharp.Quotations.ExprShape.RebuildShapeCombination
val empty<'T (requires comparison)> : Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.empty
val nbe : expr:Expr<'a> -> Expr<'a>

Full name: Script.nbe


 Apply normalization-by-evaluation to quotation tree
val expr : Expr<'a>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
static member Expr.Cast : source:Expr -> Expr<'T>
val nbe_decompile : expr:Expr<'a> -> string

Full name: Script.nbe_decompile
namespace Swensen
namespace Swensen.Unquote
module Operators

from Swensen.Unquote
val decompile : expr:Expr -> string

Full name: Swensen.Unquote.Operators.decompile
val f : (int option -> bool)
val x : int option
val mutable y : int
val f : (int -> int)
val x : int
val z : int
val f : (int -> unit)
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
type Stream<'T> = ('T -> unit) -> unit

Full name: Script.Stream<_>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
val ofArray : (int [] -> (int -> unit) -> unit)
val xs : int []
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val k : (int -> unit)
val map : ((int -> int) -> Stream<int> -> Stream<int>)
val ts : Stream<int>
val t : int
val filter : ((int -> bool) -> Stream<int> -> Stream<int>)
val f : (int -> bool)
val iter : ((int -> unit) -> Stream<int> -> unit)
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Next Version Raw view Test code New version

More information

Link:http://fssnip.net/7Xn
Posted:4 years ago
Author:Eirik Tsarpalis
Tags: metaprogramming , quotations