Extended computation expressions without for..in..do

后端 未结 2 752
谎友^
谎友^ 2021-01-31 04:10

What I mean by extended computation expressions is computation expressions with custom keywords defined via CustomOperation attribute.

When reading about extend

2条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-31 04:57

    I'm glad you liked the IL example. The best way to understand how expressions are desugared is probably to look at the spec (though it's a bit dense...).

    There we can see that something like

    C {
        op1
        op2
    }
    

    gets desugared as follows:

    T([]op1; []op2, [], fun v -> v, true) ⇒
    CL([]op1; []op2, [], C.Yield(), false) ⇒
    CL([]op2, [], 〚 []op1, C.Yield() |][], false) ⇒
    CL([]op2, [], C.Op1(C.Yield()), false) ⇒
    〚 []op2, C.Op1(C.Yield()) 〛[] ⇒
    C.Op2(C.Op1(C.Yield()))
    

    As to why Yield() is used rather than Zero, it's because if there were variables in scope (e.g. because you used some lets, or were in a for loop, etc.), then you would get Yield (v1,v2,...) but Zero clearly can't be used this way. Note that this means adding a superfluous let x = 1 into Tomas's lr example will fail to compile, because Yield will be called with an argument of type int rather than unit.

    There's another trick which can help understand the compiled form of computation expressions, which is to (ab)use the auto-quotation support for computation expressions in F# 3. Just define a do-nothing Quote member and make Run just return its argument:

    member __.Quote() = ()
    member __.Run(q) = q
    

    Now your computation expression will evaluate to the quotation of its desugared form. This can be pretty handy when debugging things.

提交回复
热议问题