0 people like it.

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

Link:http://fssnip.net/7TG
Posted:2 months ago
Author:Eirik Tsarpalis
Tags: staging , typeshape