1

計算式で Quote メンバーを使用してワークフローを AST に変換しますが、引用が構築されるときに が実際にはシーケンスで呼び出されないようにしたいと考えていますGetEnumerator()(つまり、なんらかの形式の遅延があります)。私の使用例では、シーケンスはリモート データ ソースを表し、そのメンバーを呼び出すと、GetEnumerator()実際に外部に出てクエリを実行します。

  1. Source メンバーで暗黙的に Lazy 型を使用する (それでも Quote メンバーを使用する) 方法はありGetEnumerator()ますか?

  2. let バインディングがモジュールのプロパティとして定義され、別の関数内の変数が引用符で異なるエンティティとして扱われるのはなぜですか、つまりPropertyGetvs Value.

いくつかのテストコード...

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()

その結果、次の 2 つの引用が得られます

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,
                                      []))))])
4

1 に答える 1

2

GetEnumerator() を熱心に呼び出さず、代わりにまだ値をロードしていないように、Source メンバーで暗黙的に Lazy 型を使用する (それでも Quote メンバーを使用する) 方法はありますか?

Lazy 型を暗黙的に使用する方法はないと思います。しかし、私は質問をよく理解していません.Quoteメソッドを使用すると、取得した引用に対して任意の変換を実行できるため、引用を変換して、実際にGetEnumeratorメンバーを呼び出さないようにすることができます(もちろん、データを返す何かに置き換える必要があります...)

GetEnumerator重要なことは、クエリを作成してもメソッドが呼び出されないことです。したがって、 を呼び出さずに見積もりを取得して変換し、評価できるはずですGetEnumerator

let バインディングがモジュールのプロパティとして定義され、別の関数内の変数が引用符で異なるエンティティとして扱われるのはなぜですか、つまりPropertyGetvs Value.

モジュール内の let バインディングは静的メンバーにコンパイルされるため、引用符はこの静的メンバーへの参照をキャプチャします。ローカル変数の場合、参照をキャプチャすることはできないため、Valueノードはデータを引用符に直接埋め込みます。(実際にプロパティから現在の値を取得することでPropertyGet変換を記述できます)Value

編集:が呼び出されIEnumerableたときにスローする を作成するGetEnumeratorと、F# インタラクティブで印刷された引用にエラーが表示されます (F# インタラクティブは最初のいくつかのメンバーを出力するためにシーケンスを評価しようとするため) Value

ビルダーからメソッドを削除するとRun(引用符のみが返されるように)、これは機能するはずです (そして、「派手なソース」文字列が返されます)。

type FancySource() = 
  member x.Source = "fancy source"
  interface seq<int> with
    member x.GetEnumerator() = failwith "!" 
  interface System.Collections.IEnumerable with
    member x.GetEnumerator() = failwith "!" 

let insideLet() =
  let bar = new FancySource()
  foo { for x in bar do () }

match insideLet() with
| Patterns.Call(_, _, Patterns.Call(_, _, [Patterns.Value(:? FancySource as v, _)])::_) -> 
    v.Source
于 2013-08-23T23:18:05.770 に答える