Search code examples
typesf#programming-languagesmetaprogrammingquotations

When to favor untyped over typed quotations in F#?


F# has both typed and untyped code quotations and I wonder what are the use cases where one would choose one over the other?

Is the distinction just convenience and untyped and typed quotations are convertible to each in all cases or are typed quotations e. g. a subset of the ones possible with untyped quotations?

Are there any examples which only work with typed, but not with untyped quotations – or the other way around?


Solution

  • In general, I'd recommend using typed quotations whenever you can. As usual, the types will allow you to statically enforce some correctness conditions that might otherwise cause failures at runtime. Consider:

    let one = <@@ "one" @@>
    // exception at runtime
    let two = <@@ 1 + %%one @@>
    

    as opposed to

    let one = <@ "one" @>
    // compile time error: the type 'string' does not match the type 'int'
    let two = <@ 1 + %one @>
    

    Additionally, sometimes untyped quotations need additional type annotations in cases where typed quotations don't:

    // ok
    let l = <@ [1] @>
    let l2 = <@ List.map id %l @>
    
    // fails at runtime (obj list assumed instead of int list)
    let l = <@@ [1] @@>
    let l2 = <@@ List.map id %%l @@>
    
    // ok
    let l = <@@ [1] @@>
    let l2 = <@@ List.map (id:int->int) %%l @@>
    

    However, if you're building something extremely generic out of quotations, it may not be possible to use typed quotations (e.g. because the types aren't statically known). In that sense, untyped quotations give you more flexibility.

    Also note that it's extremely easy to convert between typed and untyped quotations as needed (upcast an Expr<_> to Expr to go from typed to untyped; use Expr.Cast to go the other way).