Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Splice types into Quotations #670
Enable splicing types into Quotations
Currently, quotations have difficulty when dealing creating expressions where types are not known at compile time.
In the following example, we desire a function which gives us an expression corresponding to creating an array with type
let replaceTypeOnCall (t : System.Type) = function | Call(o,mi,args) -> let newMI = mi.GetGenericMethodDefinition().MakeGenericMethod([|t|]) match o with | Some o -> Expr.Call(o,newMI,args) | None -> Expr.Call(newMI, args) | _ -> failwith "Called on a non-Call Expr" let makeArrayExpr (length : int) (t : Type) = <@@ Array.zeroCreate<obj> length @@> |> replaceTypeOnCall t
We require an additional helper function to modify this
An expression which adds two ints together is simple:
let add (x : Expr) (y : Expr) = <@@ (%% x : int) + (%% y : int) @@>
An expression which adds two t expressions is not possible to write using quotations.
let add (x : Expr) (y : Expr) (t : Type) = let minfo = t.GetMethod("op_Addition") Expr.Call(minfo, [x; y])
This proposal is to allow splicing of type values into quotations, using ~% operator like so:
let makeArrayExpr (length : int) (t : Type) = <@@ Array.zeroCreate<~%t> length @@>
This example is simple, it instantiates the generic
let testEquals (x : Expr) (y : Expr) (t : Type) = <@@ (%% x : ~%t) + (%% y : ~%t) @@>
This example is somewhat more complicated. We want to construct an expression which corresponds to the addition of
This process can obviously fail at runtime, but we are already in a world where the %% operator exists (which can obviously fail at runtime).
Under the hood, this ~% operator maps an expression to a free type variable. For unification to succeed, each term variable
Naturally, this formulation should complain if one of these variables escapes the scope.
<@ (%%x : ~%t) @> >>> Type variable 't escapes this scope.
Resolving operators is done as follows:
"Or" constraints such as
match s.GetMethod("op_Addition"), t.GetMethod("op_Addition") with | null, null -> failwith "No method found" | mi, null -> mi | null, mi -> mi | mi, mi -> failwith "Ambiguous"
Pros and Cons
The advantages of making this adjustment to F# are:
Much easier handling of generic functions and generic operators in quotations involving types known only at runtime.
The disadvantages of making this adjustment to F# are:
Cost of implementation.
Estimated cost (XS, S, M, L, XL, XXL): M/L
Related suggestions: (put links to related suggestions here)
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
This is a pain point that I ran into with SwaggerProvider. We generate unknown types from schemas, and then create typed Async-returning functions to make HTTP calls to retrieve those types.
This required definition of