简体   繁体   中英

Is this an F# quotations bug?

[<ReflectedDefinition>]
let rec x = (fun() -> x + "abc") ()

The sample code with the recursive value above produces the following F# compiler error:

error FS0432: [<ReflectedDefinition>] terms cannot contain uses of the prefix splice operator '%'

I can't see any slicing operator usage in the code above, looks like a bug... :)

Looks like this is the problem with the quotation via ReflectedDefinitionAttribute only, normal quotation works well:

let quotation =
    <@ let rec x = (fun() -> x + "abc") () in x @>

produces expected result with the hidden Lazy.create and Lazy.force usages:

val quotation : Quotations.Expr<string> =
   LetRecursive
   ([(x, Lambda (unitVar,
        Application
        (Lambda (unitVar0,
            Call (None,
            String op_Addition[String,String,String](String, String),
            [Call (None,
                String Force[String](Lazy`1[System.String]), // `
                [x]), Value ("abc")])),
        Value (<null>)))),
   (x, Call (None, Lazy`1[String] Create[String](FSharpFunc`2[Unit,String]), [x])),
   (x, Call (None, String Force[String](Lazy`1[String]), [x]))], x) // `

So the question is: is this an F# compiler bug or not?

I'd think that this may be caused by the treatment of recursive values in F#. As a workaround, you can turn the recursive reference into a parameter:

[<ReflectedDefinition>] 
let foo x = (fun() -> x + "abc") ()

// To construct the recursive value, you'd write:
let rec x = foo x

The last line is of course invalid (just like your original code), because you're creating an immediate recursive reference, but it should give you the idea - in reality, you'd probably enclose x in a lambda function.


EDIT Originally, I thought that the problem may be as below, but I'm not sure now (see comments).

It looks more like a (probably known) limitation to me than an unexpected bug. There is an important difference between the two versions of the code you wrote - in the first case, you're binding a public value (visible to .NET) named x while in the second case, x is just a symbol used only in the quotation.

The quotation that would have to be stored in the meta-data of the assembly would look like this:

let rec x = <@ (fun() -> %x + "abc") () @>

The body is quoted, but x is not a quoted symbol, so it needs to be spliced into the quotation (that is, it will be evaluated and the result will be used in its place). Note that this code will fail, because you're declaring a recursive value with immediate reference - x needs to be evaluated as part of its definition, so this won't work.

However, I think that % cannot appear in ReflectedDefinition quotations (that is, you cannot store the above in meta-data), because it involves some runtime aspects - you'd need to evaluate x when loading the meta-data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM