Using the Quote member on a computation expression to convert the workflow into an AST, but would like it be such that the GetEnumerator()
is not actually called on the sequence as the quotation is constructed (i.e., have some form of laziness). In my use case, the sequence represents a remote data-source, and invoking the GetEnumerator()
member on it will actually go out and query against it.
Is there some way to implicitly use the Lazy type (and still use the Quote member) on the Source member so that it does not eagerly call
GetEnumerator()
and instead has simply not loaded the value yet?Why is a let binding defined as a property of a module and a variable within another function treated as different entities in the quotation, i.e.
PropertyGet
vsValue
.
Some test code...
module Example
open Microsoft.FSharp.Quotations
[<Interface>]
type I<'Type> =
inherit seq<'Type>
type FooBuilder() =
member __.Source (x : #seq<'Type>) : I<'Type> = invalidOp "not implemented"
member __.For (source : I<'Type>, f : 'Type -> I<'Type>) : I<'Type> = invalidOp "not implemented"
member __.Zero () : I<'Type> = invalidOp "not implemented"
member __.Quote (expr : Expr<#seq<'Type>>) = expr
member __.Run (expr : Expr<#seq<'Type>>) =
System.Console.WriteLine(expr)
let foo = FooBuilder()
let bar = [1; 2; 3]
foo {
for x in bar do ()
}
let insideLet() =
let bar = [1; 2; 3]
foo {
for x in bar do ()
}
insideLet()
which results in the following two quotations
Call (Some (Value (FSI_0009+FooBuilder)), For,
[Call (Some (Value (FSI_0009+FooBuilder)), Source,
[PropertyGet (None, bar, [])]),
Lambda (_arg1,
Let (x, _arg1,
Sequential (Value (<null>),
Call (Some (Value (FSI_0009+FooBuilder)), Zero,
[]))))])
Call (Some (Value (FSI_0009+FooBuilder)), For,
[Call (Some (Value (FSI_0009+FooBuilder)), Source, [Value ([1; 2; 3])]),
Lambda (_arg1,
Let (x, _arg1,
Sequential (Value (<null>),
Call (Some (Value (FSI_0009+FooBuilder)), Zero,
[]))))])