5

このコードは、 「Lazyv.Yield」という論文に基づいています。データストリームのプロデューサーとコンシューマーを切り離す方法についてです。コードのHaskellの部分は理解していますが、O'Caml / F#ではわかりません。次の理由でこのコードを理解していません。

引数として例外を取り、単位を返す関数にはどのような動作が期待できますか?

消費者はどのように特定の例外に投影しますか?(どういう意味ですか?)

消費者の例は何でしょうか?

module SimpleGenerators

type 'a gen        = unit -> 'a
type producer      = unit gen
type consumer      = exn -> unit  (* consumer will project into specific exception *)
type 'a transducer = 'a gen -> 'a gen 

let yield_handler : (exn -> unit) ref = 
    ref (fun _ -> failwith "yield handler is not set")

let iterate (gen : producer) (consumer : consumer) : unit = 
    let oldh = !yield_handler in
    let rec newh x =
        try 
            yield_handler := oldh
            consumer x
            yield_handler := newh
        with e -> yield_handler := newh; raise e
    in
    try
        yield_handler := newh
        let r = gen () in
        yield_handler := oldh
        r
    with e -> yield_handler := oldh; raise e
4

2 に答える 2

4

私はその論文に精通していないので、他の人はおそらくもっと啓発的でしょう。それまでの間、いくつかの簡単な回答/推測があります。

タイプの関数exn -> unitは基本的に例外ハンドラです。

例外にはデータが含まれる場合があります。これらは、そのようにポリモーフィックバリアントに非常に似ています。つまり、必要なときにいつでも新しい例外を追加でき、データコンストラクターとして機能できます。

消費者は、必要なデータを提供する特定の例外を探しているようです。その他はただリレイズします。したがって、それは可能な例外の空間の予測を見ているだけです(私は推測します)。

于 2012-10-30T19:31:49.627 に答える
3

OCamlサンプルは、F#では通常使用しないいくつかの構造とデザインパターンを使用していると思います。したがって、OCaml固有のものです。Jeffreyが言うように、OCamlプログラムは制御フローに例外を使用することがよくあります(F#では例外的な状況でのみ使用されます)。

また、F#には非常に強力なシーケンス式メカニズムがあり、データのプロデューサーとデータのコンシューマーを区別するために非常にうまく使用できます。私はこの論文を詳しく読んでいなかったので、もっと複雑なものがあるかもしれませんが、F#の簡単な例は次のようになります。

// Generator: Produces infinite sequence of numbers from 'start'
// and prints the numbers as they are being generated (to show I/O behaviour)
let rec numbers start = seq { 
  printfn "generating: %d" start
  yield start
  yield! numbers (start + 1) }

for単純なコンシューマーはループを使用して実装できますが、ストリームを消費する場合は、以下を使用して消費する要素の数を指定する必要がありSeq.takeます。

// Consumer: takes a sequence of numbers generated by the 
// producer and consumes first 100 elements 
let consumer nums = 
  for n in nums |> Seq.take 100 do
    printfn "consuming: %d" n

コードを実行するconsumer (numbers 0)と、印刷が開始されます。

generating: 0
consuming: 0
generating: 1
consuming: 1
generating: 2
consuming: 2

したがって、プロデューサーとコンシューマーの効果が交互に配置されていることがわかります。これは非常にシンプルで強力なメカニズムだと思いますが、おそらく私は論文の要点を見逃しており、さらに興味深いものがあります。もしそうなら、私に知らせてください!慣用的なF#ソリューションは、おそらく上記と非常によく似ていると思いますが。

于 2012-10-31T02:30:41.273 に答える