Skip to content

Instantly share code, notes, and snippets.

@kevmal
Last active September 6, 2018 22:30
Show Gist options
  • Save kevmal/e29dbf6431af2e23f26d6480f8e17b82 to your computer and use it in GitHub Desktop.
Save kevmal/e29dbf6431af2e23f26d6480f8e17b82 to your computer and use it in GitHub Desktop.
open Microsoft.FSharp.Quotations
open System
type TypeTemplate() =
static member create ([<ReflectedDefinition(false)>] f : Expr<'a -> 'b>) : Type list -> ('a -> 'b) =
let rec extractCall e =
match e with
| Patterns.Lambda(_,body) -> extractCall body
| Patterns.Call(_o,minfo,_args) -> minfo
| _ -> failwithf "Expression not of expected form %A" e
let rec replaceMethod minfo e =
match e with
| Patterns.Lambda(v,body) -> Expr.Lambda(v, replaceMethod minfo body)
| Patterns.Call(Some o,_,args) -> Expr.Call(o,minfo,args)
| Patterns.Call(None,_,args) -> Expr.Call(minfo,args)
| _ -> failwithf "Expression not of expected form %A" e
match f with
| Patterns.Lambda (_,e) ->
let minfo = extractCall e
let makeMethod =
if minfo.IsGenericMethod then
let minfodef = minfo.GetGenericMethodDefinition()
fun types ->
minfodef.MakeGenericMethod(types |> Seq.toArray)
else
fun _ -> minfo
fun types ->
let method = makeMethod types
let lambda = replaceMethod method f
FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation lambda :?> ('a -> 'b)
| _ -> failwithf "Expression not of expected form %A" f
//Example
let testExpr<'t1,'t2,'t3> arg1 arg2 arg3 =
<@@
printfn "%s" ((%%arg1 : 't1).ToString())
printfn "%s" ((%%arg2 : 't2).ToString())
printfn "%s" ((%%arg3 : 't3).ToString())
@@>
let bleh =
<@@
printfn "bleh"
%%(TypeTemplate.create testExpr<_,_,_> [typeof<string>; typeof<double>; typeof<int>] <@@"bleh"@@> <@@1.0@@> <@@5@@>) : unit
@@>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment