5

这段代码来自一篇名为“Lazy v. 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循环来实现,但是如果我们想消费流,我们需要说明要消费多少元素 using 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 回答