0 people like it.
Like the snippet!
Staged Generic Hashcode generation with recursive type support
Staged Generic Programming with support for recursive types PoC
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:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
|
open FSharp.Quotations
open FSharp.Quotations.Evaluator
open Swensen.Unquote
open TypeShape
open TypeShape_StagingExtensions
// Rank-2 encoding of staged hashcode generator
type StagedHashCodeGenerator =
abstract Generate<'T> : Expr<'T> -> Expr<int>
// Variation of the Y combinator for generic staged hashode generators
let Y : (StagedHashCodeGenerator -> StagedHashCodeGenerator) -> StagedHashCodeGenerator =
fun F ->
let rec aux (stack : Var list) (e : Expr<'a>) : Expr<int> =
match stack |> List.tryFind (fun v -> v.Type = typeof<'a -> int>) with
| None ->
// first time this type occurs in the stack, push fresh function variable
// into stack and perform staged computation
let selfVar = Var("func", typeof<'a -> int>)
let tVar = Var("t", typeof<'a>)
let nestedGen = mkRecursiveGen (selfVar :: stack)
// generate the staged body for the given type
let body = nestedGen.Generate (Expr.Cast<'a> (Expr.Var tVar))
// check whether type has been called recursively in the staged expression tree
if body.GetFreeVars() |> Seq.exists ((=) selfVar) then
// we are looking at a recursive type, wrap body inside a recursive function declaration
let lambda = Expr.Lambda(tVar, body)
let recExpr = Expr.Cast<'a -> int>(Expr.LetRecursive([selfVar, lambda], Expr.Var selfVar))
<@ (%recExpr) %e @>
else
// not a recursive type, just replace input variable with input expression
Expr.Cast<_>(body.Substitute(function v when v = tVar -> Some (e :> _) | _ -> None))
| Some self ->
// we are already inside a recursive call, just invoke the recursive function argument
let selfExpr = Expr.Cast<'a -> int>(Expr.Var self)
<@ (%selfExpr) %e @>
and mkRecursiveGen stack : StagedHashCodeGenerator =
F { new StagedHashCodeGenerator with member __.Generate e = aux stack e }
mkRecursiveGen []
// The generic program itself
let rec mkStagedHasher() =
Y (fun self -> { new StagedHashCodeGenerator with member __.Generate expr = mkStagedHasherAux self expr })
and private mkStagedHasherAux<'T> (self : StagedHashCodeGenerator) (expr : Expr<'T>) : Expr<int> =
let unwrap () = unbox<Expr<'a>> expr
let genHash () = Expr.lam (fun e -> self.Generate<'a> e)
let combineHash (h1 : Expr<int>) (h2 : Expr<int>) =
<@ let h1 = %h1 in let h2 = %h2 in ((h1 <<< 5) + h1) ||| h2 @>
let stageMemberHash (shape : IShapeMember<'DeclaringType>) (dExpr : Expr<'DeclaringType>) =
shape.Accept { new IMemberVisitor<'DeclaringType, Expr<int>> with
member __.Visit (shape : ShapeMember<'DeclaringType, 'FieldType>) =
let fExpr = shape.ProjectExpr dExpr
self.Generate fExpr }
match shapeof<'T> with
| Shape.Unit -> <@ 0 @>
| Shape.Bool -> <@ if (% unwrap() ) then 1 else 0 @>
| Shape.Int32 -> <@ (% unwrap()) @>
| Shape.Double -> <@ hash<double> (% unwrap()) @>
| Shape.String -> <@ hash<string> (% unwrap()) @>
| Shape.Array s when s.Rank = 1 ->
s.Accept { new IArrayVisitor<Expr<int>> with
member __.Visit<'t> _ =
<@
match (% (unwrap() : Expr<'t[]>)) with
| null -> 0
| ts ->
let mutable agg = 0
for t in ts do
let th = (% genHash() ) t
agg <- (% Expr.lam2 combineHash) agg th
agg
@> }
| Shape.FSharpOption s ->
s.Accept { new IFSharpOptionVisitor<Expr<int>> with
member __.Visit<'t> () =
<@
match (% (unwrap() : Expr<'t option>)) with
| None -> 0
| Some t ->
let th = (% genHash() ) t
(% Expr.lam2 combineHash) 1 th
@> }
| Shape.FSharpList s ->
s.Accept { new IFSharpListVisitor<Expr<int>> with
member __.Visit<'t> () =
<@
let mutable agg = 0
let mutable ts = (% (unwrap() : Expr<'t list>))
while not(List.isEmpty ts) do
let th = (% genHash() ) (List.head ts)
agg <- (% Expr.lam2 combineHash) agg th
ts <- List.tail ts
agg
@> }
| Shape.Tuple (:? ShapeTuple<'T> as shape) ->
let mkElementHasher tuple =
shape.Elements
|> Array.map (fun e -> stageMemberHash e tuple)
|> Array.map (fun eh agg -> combineHash eh agg)
|> Expr.update ("agg", <@ 0 @>)
<@
let tuple = %expr
(% Expr.lam mkElementHasher) tuple
@>
| Shape.FSharpRecord (:? ShapeFSharpRecord<'T> as shape) ->
let mkFieldHasher record =
shape.Fields
|> Array.map (fun e -> stageMemberHash e record)
|> Array.map (fun eh agg -> combineHash eh agg)
|> Expr.update ("agg", <@ 0 @>)
<@
let record = %expr
(% Expr.lam mkFieldHasher) record
@>
| Shape.FSharpUnion (:? ShapeFSharpUnion<'T> as shape) ->
let stageUnionCaseHasher
(union : Expr<'T>) (tag : Expr<int>)
(case : ShapeFSharpUnionCase<'T>) =
case.Fields
|> Array.map (fun c -> stageMemberHash c union)
|> Array.map (fun fh agg -> combineHash fh agg)
|> Expr.update ("agg", tag)
let stageUnionCaseHashers (u : Expr<'T>) (tag : Expr<int>) =
shape.UnionCases
|> Array.map (stageUnionCaseHasher u tag)
|> Expr.switch tag
<@
let union = %expr
let tag = (% Expr.lam shape.GetTagExpr) union
(% Expr.lam2 stageUnionCaseHashers) union tag
@>
| _ -> failwithf "Unsupported shape %O" typeof<'T>
// Compilation code
let mkHashCodeExpr<'T> () =
fun e -> mkStagedHasher().Generate<'T> e
|> Expr.lam
|> Expr.cleanup
let mkHasher<'T> () = mkHashCodeExpr<'T>() |> QuotationEvaluator.Evaluate
let decompileHasher<'T> () = mkHashCodeExpr<'T>() |> decompile
// examples
let hasher1 = mkHasher<int list * string option>()
hasher1 ([1 .. 100], Some "42")
decompileHasher<int * (string * bool)>()
//fun t ->
// let mutable agg = 0
// agg <- let h1 = t.m_Item1 in (h1 <<< 5) + h1 ||| agg
// agg <-
// let h1 =
// let tuple = t.m_Item2
// let mutable agg = 0
// agg <- let h1 = hash tuple.m_Item1 in (h1 <<< 5) + h1 ||| agg
// agg <- let h1 = if tuple.m_Item2 then 1 else 0 in (h1 <<< 5) + h1 ||| agg
// agg
// (h1 <<< 5) + h1 ||| agg
// agg
type Foo = { A : int ; B : string }
type Bar =
| UA
| UB of foo:string
| UC of Foo
let hasher2 = mkHasher<Bar list>()
hasher2 [UA ; UC { A = 12 ; B = "test" }; UB "string" ]
decompileHasher<Bar>()
//fun t ->
// let tag = t.Tag
// if tag = 0 then tag
// elif tag = 1 then
// let mutable agg = tag
// agg <- let h1 = hash t._foo in (h1 <<< 5) + h1 ||| agg
// agg
// elif tag = 2 then
// let mutable agg = tag
// agg <-
// let h1 =
// let record = t.item
// let mutable agg = 0
// agg <- let h1 = record.A@ in (h1 <<< 5) + h1 ||| agg
// agg <- let h1 = record.B@.GetHashCode() in (h1 <<< 5) + h1 ||| agg
// agg
// (h1 <<< 5) + h1 ||| agg
// agg
// else invalidOp "invalid tag"
type P = Z | S of P
let hasher3 = mkHasher<P>()
hasher3 (S (S (S (S (S Z)))))
decompileHasher<P> ()
//fun t ->
// let rec func t =
// let tag = t.Tag
// if tag = 0 then tag
// elif tag = 1 then
// let mutable agg = tag
// agg <- let h1 = func t.item in (h1 <<< 5) + h1 ||| agg
// agg
// else invalidOp "invalid tag"
//
// func t
|
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Quotations
--------------------
namespace Microsoft.FSharp.Quotations
namespace FSharp.Quotations.Evaluator
namespace Swensen
namespace Swensen.Unquote
module TypeShape
module TypeShape_StagingExtensions
type StagedHashCodeGenerator =
interface
abstract member Generate : Expr<'T> -> Expr<int>
end
Full name: Script.StagedHashCodeGenerator
abstract member StagedHashCodeGenerator.Generate : Expr<'T> -> Expr<int>
Full name: Script.StagedHashCodeGenerator.Generate
Multiple items
module Expr
from TypeShape_StagingExtensions
--------------------
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<_>
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 Y : F:(StagedHashCodeGenerator -> StagedHashCodeGenerator) -> StagedHashCodeGenerator
Full name: Script.Y
val F : (StagedHashCodeGenerator -> StagedHashCodeGenerator)
val aux : (Var list -> Expr<'a> -> Expr<int>)
val stack : Var list
Multiple items
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:System.Type * ?isMutable:bool -> Var
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val e : Expr<'a>
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 tryFind : predicate:('T -> bool) -> list:'T list -> 'T option
Full name: Microsoft.FSharp.Collections.List.tryFind
val v : Var
property Var.Type: System.Type
val typeof<'T> : System.Type
Full name: Microsoft.FSharp.Core.Operators.typeof
union case Option.None: Option<'T>
val selfVar : Var
val tVar : Var
val nestedGen : StagedHashCodeGenerator
val mkRecursiveGen : (Var list -> StagedHashCodeGenerator)
val body : Expr<int>
abstract member StagedHashCodeGenerator.Generate : Expr<'T> -> Expr<int>
static member Expr.Cast : source:Expr -> Expr<'T>
static member Expr.Var : variable:Var -> Expr
member Expr.GetFreeVars : unit -> seq<Var>
module Seq
from Microsoft.FSharp.Collections
val exists : predicate:('T -> bool) -> source:seq<'T> -> bool
Full name: Microsoft.FSharp.Collections.Seq.exists
val lambda : Expr
static member Expr.Lambda : parameter:Var * body:Expr -> Expr
val recExpr : Expr<('a -> int)>
static member Expr.LetRecursive : bindings:(Var * Expr) list * body:Expr -> Expr
member Expr.Substitute : substitution:(Var -> Expr option) -> Expr
union case Option.Some: Value: 'T -> Option<'T>
val self : Var
val selfExpr : Expr<('a -> int)>
val e : Expr<'b>
val mkStagedHasher : unit -> StagedHashCodeGenerator
Full name: Script.mkStagedHasher
val self : StagedHashCodeGenerator
val expr : Expr<'a>
val private mkStagedHasherAux : self:StagedHashCodeGenerator -> expr:Expr<'T> -> Expr<int>
Full name: Script.mkStagedHasherAux
val expr : Expr<'T>
val unwrap : (unit -> Expr<'a>)
val unbox : value:obj -> 'T
Full name: Microsoft.FSharp.Core.Operators.unbox
val genHash : (unit -> Expr<('a -> int)>)
val lam : f:(Expr<'T> -> Expr<'S>) -> Expr<('T -> 'S)>
Full name: TypeShape_StagingExtensions.Expr.lam
val combineHash : (Expr<int> -> Expr<int> -> Expr<int>)
val h1 : Expr<int>
val h2 : Expr<int>
val h1 : int
val h2 : int
val stageMemberHash : (IShapeMember<'DeclaringType> -> Expr<'DeclaringType> -> Expr<int>)
val shape : IShapeMember<'DeclaringType>
Multiple items
type IShapeMember =
interface
abstract member IsPublic : bool
abstract member IsStructMember : bool
abstract member Label : string
abstract member Member : TypeShape
abstract member MemberInfo : MemberInfo
end
Full name: TypeShape.IShapeMember
--------------------
type IShapeMember<'DeclaringType> =
interface
inherit IShapeMember
abstract member Accept : IMemberVisitor<'DeclaringType,'R> -> 'R
end
Full name: TypeShape.IShapeMember<_>
val dExpr : Expr<'DeclaringType>
abstract member IShapeMember.Accept : IMemberVisitor<'DeclaringType,'R> -> 'R
type IMemberVisitor<'DeclaringType,'R> =
interface
abstract member Visit : ShapeMember<'DeclaringType,'MemberType> -> 'R
end
Full name: TypeShape.IMemberVisitor<_,_>
val shape : ShapeMember<'DeclaringType,'a>
type ShapeMember<'DeclaringType,'MemberType> =
interface IShapeMember<'DeclaringType>
private new : label:string * memberInfo:MemberInfo * path:MemberInfo [] -> ShapeMember<'DeclaringType,'MemberType>
member Project : instance:'DeclaringType -> 'MemberType
member ProjectExpr : instance:Expr<'DeclaringType> -> Expr<'MemberType>
member IsPublic : bool
member IsStructMember : bool
member Label : string
member MemberInfo : MemberInfo
Full name: TypeShape.ShapeMember<_,_>
val fExpr : Expr<'a>
member ShapeMember.ProjectExpr : instance:Expr<'DeclaringType> -> Expr<'MemberType>
val shapeof<'T> : TypeShape
Full name: TypeShape.shapeof
module Shape
from TypeShape
active recognizer Unit: TypeShape -> unit option
Full name: TypeShape.Shape.( |Unit|_| )
active recognizer Bool: TypeShape -> unit option
Full name: TypeShape.Shape.( |Bool|_| )
active recognizer Int32: TypeShape -> unit option
Full name: TypeShape.Shape.( |Int32|_| )
active recognizer Double: TypeShape -> unit option
Full name: TypeShape.Shape.( |Double|_| )
val hash : obj:'T -> int (requires equality)
Full name: Microsoft.FSharp.Core.Operators.hash
Multiple items
val double : value:'T -> double (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.double
--------------------
type double = System.Double
Full name: Microsoft.FSharp.Core.double
active recognizer String: TypeShape -> unit option
Full name: TypeShape.Shape.( |String|_| )
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
active recognizer Array: TypeShape -> IShapeArray option
Full name: TypeShape.Shape.( |Array|_| )
val s : IShapeArray
property IShapeArray.Rank: int
abstract member IShapeArray.Accept : IArrayVisitor<'R> -> 'R
type IArrayVisitor<'R> =
interface
abstract member Visit : rank:int -> 'R
end
Full name: TypeShape.IArrayVisitor<_>
val ts : 't []
val mutable agg : int
val t : 't
val th : int
val lam2 : f:(Expr<'T1> -> Expr<'T2> -> Expr<'S>) -> Expr<('T1 -> 'T2 -> 'S)>
Full name: TypeShape_StagingExtensions.Expr.lam2
active recognizer FSharpOption: TypeShape -> IShapeFSharpOption option
Full name: TypeShape.Shape.( |FSharpOption|_| )
val s : IShapeFSharpOption
abstract member IShapeFSharpOption.Accept : IFSharpOptionVisitor<'R> -> 'R
type IFSharpOptionVisitor<'R> =
interface
abstract member Visit : unit -> 'R
end
Full name: TypeShape.IFSharpOptionVisitor<_>
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
active recognizer FSharpList: TypeShape -> IShapeFSharpList option
Full name: TypeShape.Shape.( |FSharpList|_| )
val s : IShapeFSharpList
abstract member IShapeFSharpList.Accept : IFSharpListVisitor<'R> -> 'R
type IFSharpListVisitor<'R> =
interface
abstract member Visit : unit -> 'R
end
Full name: TypeShape.IFSharpListVisitor<_>
val mutable ts : 't list
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
val isEmpty : list:'T list -> bool
Full name: Microsoft.FSharp.Collections.List.isEmpty
val head : list:'T list -> 'T
Full name: Microsoft.FSharp.Collections.List.head
val tail : list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.tail
active recognizer Tuple: TypeShape -> IShapeTuple option
Full name: TypeShape.Shape.( |Tuple|_| )
type ShapeTuple<'Tuple> =
interface IShapeTuple
private new : unit -> ShapeTuple<'Tuple>
member CreateUninitialized : unit -> 'Tuple
member CreateUninitializedExpr : unit -> Expr<'Tuple>
member Elements : IShapeWriteMember<'Tuple> []
member IsStructTuple : bool
Full name: TypeShape.ShapeTuple<_>
val shape : ShapeTuple<'T>
val mkElementHasher : (Expr<'T> -> Expr<int>)
val tuple : Expr<'T>
property ShapeTuple.Elements: IShapeWriteMember<'T> []
Multiple items
union case TypeShapeInfo.Array: element: System.Type * rank: int -> TypeShapeInfo
--------------------
module Array
from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []
Full name: Microsoft.FSharp.Collections.Array.map
val e : IShapeWriteMember<'T>
val eh : Expr<int>
val agg : Expr<int>
val update : varName:string * init:Expr<'T> -> comps:(Expr<'T> -> Expr<'T>) [] -> Expr<'T>
Full name: TypeShape_StagingExtensions.Expr.update
val tuple : 'T
active recognizer FSharpRecord: TypeShape -> IShapeFSharpRecord option
Full name: TypeShape.Shape.( |FSharpRecord|_| )
type ShapeFSharpRecord<'Record> =
interface IShapeFSharpRecord
private new : unit -> ShapeFSharpRecord<'Record>
member CreateUninitialized : unit -> 'Record
member CreateUninitializedExpr : unit -> Expr<'Record>
member Fields : IShapeWriteMember<'Record> []
member IsStructRecord : bool
Full name: TypeShape.ShapeFSharpRecord<_>
val shape : ShapeFSharpRecord<'T>
val mkFieldHasher : (Expr<'T> -> Expr<int>)
val record : Expr<'T>
property ShapeFSharpRecord.Fields: IShapeWriteMember<'T> []
val record : 'T
active recognizer FSharpUnion: TypeShape -> IShapeFSharpUnion option
Full name: TypeShape.Shape.( |FSharpUnion|_| )
type ShapeFSharpUnion<'U> =
interface IShapeFSharpUnion
private new : unit -> ShapeFSharpUnion<'U>
member GetTag : caseName:string -> int
member GetTag : union:'U -> int
member GetTagExpr : union:Expr<'U> -> Expr<int>
member IsStructUnion : bool
member UnionCases : ShapeFSharpUnionCase<'U> []
Full name: TypeShape.ShapeFSharpUnion<_>
val shape : ShapeFSharpUnion<'T>
val stageUnionCaseHasher : (Expr<'T> -> Expr<int> -> ShapeFSharpUnionCase<'T> -> Expr<int>)
val union : Expr<'T>
val tag : Expr<int>
val case : ShapeFSharpUnionCase<'T>
type ShapeFSharpUnionCase<'Union> =
interface IShapeFSharpUnionCase
private new : uci:UnionCaseInfo -> ShapeFSharpUnionCase<'Union>
member CreateUninitialized : unit -> 'Union
member CreateUninitializedExpr : unit -> Expr<'Union>
member CaseInfo : UnionCaseInfo
member Fields : IShapeWriteMember<'Union> []
Full name: TypeShape.ShapeFSharpUnionCase<_>
property ShapeFSharpUnionCase.Fields: IShapeWriteMember<'T> []
val c : IShapeWriteMember<'T>
val fh : Expr<int>
val stageUnionCaseHashers : (Expr<'T> -> Expr<int> -> Expr<int>)
val u : Expr<'T>
property ShapeFSharpUnion.UnionCases: ShapeFSharpUnionCase<'T> []
val switch : tag:Expr<int> -> cases:Expr<'T> [] -> Expr<'T>
Full name: TypeShape_StagingExtensions.Expr.switch
val union : 'T
val tag : int
member ShapeFSharpUnion.GetTagExpr : union:Expr<'U> -> Expr<int>
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
val mkHashCodeExpr : unit -> Expr<('T -> int)>
Full name: Script.mkHashCodeExpr
val e : Expr<'T>
val cleanup : expr:Expr<'T> -> Expr<'T>
Full name: TypeShape_StagingExtensions.Expr.cleanup
val mkHasher : unit -> ('T -> int)
Full name: Script.mkHasher
type QuotationEvaluator
static member CompileUntyped : Expr -> obj
static member Evaluate : Expr<'T> -> 'T
static member EvaluateUntyped : Expr -> obj
static member private EvaluateUntypedUsingQueryApproximations : Expr -> obj
static member ToLinqExpression : Expr -> Expression
Full name: FSharp.Quotations.Evaluator.QuotationEvaluator
static member QuotationEvaluator.Evaluate : Expr<'T> -> 'T
val decompileHasher<'T> : unit -> string
Full name: Script.decompileHasher
val decompile : expr:Expr -> string
Full name: Swensen.Unquote.Operators.decompile
val hasher1 : (int list * string option -> int)
Full name: Script.hasher1
type bool = System.Boolean
Full name: Microsoft.FSharp.Core.bool
type Foo =
{A: int;
B: string;}
Full name: Script.Foo
Foo.A: int
Foo.B: string
type Bar =
| UA
| UB of foo: string
| UC of Foo
Full name: Script.Bar
union case Bar.UA: Bar
union case Bar.UB: foo: string -> Bar
union case Bar.UC: Foo -> Bar
val hasher2 : (Bar list -> int)
Full name: Script.hasher2
type P =
| Z
| S of P
Full name: Script.P
union case P.Z: P
union case P.S: P -> P
val hasher3 : (P -> int)
Full name: Script.hasher3
More information