FSharp.Quotations.Compiler


Limitations

This library has some limitations.

Not Implemented Yet

  • ForIntegerRangeLoop
  • LetRecursive
  • NewDelegate
  • WhileLoop

Unupported

  • AddressOf
  • AddressSet
  • Quote

Technical Problem

inline function

The inline functions that contains other inline function with NoDynamicInvocationAttribute can not invoke. For example, the following code throws System.NotSupportedException.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
// (-) has NoDynamicInvocationAttribute.
let inline f1 x y = x - y
try
  let expr = <@ f1 20 10 @>
  expr.Execute() |> ignore
with
  :? System.NotSupportedException -> printfn "raised exception."

Of course, the inline function with NoDynamicInvocationAttribute can not execute using this library.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
[<NoDynamicInvocationAttribute >]
let inline f2 x = x
try
  let expr = <@ f2 10 @>
  expr.Execute() |> ignore
with
  :? System.NotSupportedException -> printfn "raised exception."

If you want to execute the function that contains other inline function with NoDynamicInvocationAttribute, you need to remove inline or to inline by hand.

1: 
2: 
let expr = <@ 20 - 10 @>
printfn "20 - 10 = %d" (expr.Execute())

In other case, the inline functions that contains member constraint invocation expressions can not also execute by this library. There is no workarround.

mutable and try-with/try-finally

This library wraps try-with and try-finally in the lambda expression because they are expression that has the value.

1: 
2: 
3: 
4: 
5: 
6: 
let tryWithExpr =
  <@ let x = 10
     let res =
       try x with _ -> 20
     res * 2 @>
let compiledTryWithExpr = tryWithExpr.Compile()

It is compiled as following.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type lambda0(x) =
  inherit FSharpFunc<unit, int>()

  override __.Invoke(_) =
    try x with _ -> 20

let x = 10
let res = lambda0(x).Invoke()
res * 2

The x is compiled to the field of the lambda class. So rewrite the x in the body of the lambda expression, it does not affect the outside of the lambda expression.

1: 
2: 
3: 
4: 
5: 
6: 
let letMutableAndTryWithExpr =
  <@ let mutable y = 0
     let res2 =
       try y <- 10; y with _ -> 20
     (y, res2) @>
let compiledLetMutableAndTryWithExpr = letMutableAndTryWithExpr.Compile()

It is compiled as following.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
type lambda1(y) =
  inherit FSharpFunc<unit, int>()

  member val y = y with get, set
  override this.Invoke(_) =
    try this.y <- 10; y with _ -> 20

let mutable y = 0
let tmp = lambda1(y)
let res2 = tmp.Invoke()
// should assign after invocation of the lambda expression.
// But now implementation does not assign.
// y <- tmp.y
(y, res2)

Expr.Value

The Expr.Value is not supported the type that does not have the literal.

1: 
2: 
3: 
let valueExpr: Expr<System.DateTime> =
  Expr.Value(System.DateTime.UtcNow)
  |> Expr.Cast
1: 
2: 
3: 
4: 
try
  valueExpr.Execute() |> ignore
with
  e -> printfn "%A" e.Message
"unsupported value type: System.DateTime"

You should use the quoted expression instead of using the Expr.Value.

1: 
let codeQuote = <@ System.DateTime.UtcNow @>
1: 
printfn "%A" (codeQuote.Execute())

The above quoted expression can execute as expected because it is evaluated as Expr.PropertyGet rather than Expr.Value.

2015/09/09 4:20:16
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Quotations
namespace FSharp
namespace FSharp.Quotations
namespace FSharp.Quotations.Compiler
val f1 : x:'a -> y:'b -> 'c (requires member ( - ))

Full name: Limitations.f1
val x : 'a (requires member ( - ))
val y : 'b (requires member ( - ))
val expr : Expr<int>
member Expr.Execute : unit -> 'T
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
namespace System
Multiple items
type NotSupportedException =
  inherit SystemException
  new : unit -> NotSupportedException + 2 overloads

Full name: System.NotSupportedException

--------------------
System.NotSupportedException() : unit
System.NotSupportedException(message: string) : unit
System.NotSupportedException(message: string, innerException: exn) : unit
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Multiple items
type NoDynamicInvocationAttribute =
  inherit Attribute
  new : unit -> NoDynamicInvocationAttribute

Full name: Microsoft.FSharp.Core.NoDynamicInvocationAttribute

--------------------
new : unit -> NoDynamicInvocationAttribute
val f2 : x:'a -> 'a

Full name: Limitations.f2
val x : 'a
val expr : Expr<int>

Full name: Limitations.expr
val tryWithExpr : Expr<int>

Full name: Limitations.tryWithExpr
val x : int
val res : int
val compiledTryWithExpr : ICompiledCode<int>

Full name: Limitations.compiledTryWithExpr
member Expr.Compile : unit -> ICompiledCode<'T>
Multiple items
type lambda0 =
  inherit FSharpFunc<unit,int>
  new : x:int -> lambda0
  override Invoke : unit -> int

Full name: Limitations.lambda0

--------------------
new : x:int -> lambda0
new : unit -> FSharpFunc<'T,'U>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
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<_>
override lambda0.Invoke : unit -> int

Full name: Limitations.lambda0.Invoke
val x : int

Full name: Limitations.x
val res : int

Full name: Limitations.res
val letMutableAndTryWithExpr : Expr<int * int>

Full name: Limitations.letMutableAndTryWithExpr
val mutable y : int
val res2 : int
val compiledLetMutableAndTryWithExpr : ICompiledCode<int * int>

Full name: Limitations.compiledLetMutableAndTryWithExpr
Multiple items
type lambda1 =
  inherit FSharpFunc<unit,int>
  new : y:int -> lambda1
  override Invoke : unit -> int
  member y : int
  member y : int with set

Full name: Limitations.lambda1

--------------------
new : y:int -> lambda1
val y : int
member lambda1.y : int

Full name: Limitations.lambda1.y
val set : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
val this : lambda1
override lambda1.Invoke : unit -> int

Full name: Limitations.lambda1.Invoke
property lambda1.y: int
val mutable y : int

Full name: Limitations.y
val tmp : lambda1

Full name: Limitations.tmp
val res2 : int

Full name: Limitations.res2
override lambda1.Invoke : unit -> int
val valueExpr : Expr<System.DateTime>

Full name: Limitations.valueExpr
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<_>
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
System.DateTime()
   (+0 other overloads)
System.DateTime(ticks: int64) : unit
   (+0 other overloads)
System.DateTime(ticks: int64, kind: System.DateTimeKind) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, calendar: System.Globalization.Calendar) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: System.DateTimeKind) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: System.Globalization.Calendar) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: System.DateTimeKind) : unit
   (+0 other overloads)
static member Expr.Value : value:'T -> Expr
static member Expr.Value : value:obj * expressionType:System.Type -> Expr
property System.DateTime.UtcNow: System.DateTime
static member Expr.Cast : source:Expr -> Expr<'T>
val e : exn
property System.Exception.Message: string
val codeQuote : Expr<System.DateTime>

Full name: Limitations.codeQuote
Fork me on GitHub