13

管道是一个非常优雅、非常简单的迭代版本。您可以使用原语awaityield. Paolo Capriotti 扩展了带有受保护管道的管道的概念,它使用了稍微复杂的tryAwait原语,它允许管道在输入流用完后执行一些终结。

受保护的管道实现await在以下方面重新定义tryAwait

await = tryAwait >>= maybe discard return

我的问题是:如果我编写针对更简单的管道实现的代码(使用awaitand yield),使用相同的代码,如果我切换到受保护的管道实现,它的行为是否相同?换句话说,就行为而言,受保护的管道代码可以简单地视为管道代码的超集吗?

4

2 回答 2

11

这是加布里埃尔,他发布了管道。我一直在与 Paolo 合作,我们在作品中有一个更优雅的实现,它比他最初的提议更强大和类型安全。您的问题的简短回答是最终实现是原始管道的超集,您可以编写与以前相同的代码,具有相同的行为和语义。

我什至可以在这里简单地总结一下。Await 和 yield 语句是管道可以放弃控制的唯一方式,因此如果上游或下游管道终止,我们会为每个语句附加一个回退。回退会永久降级管道,并且不能再重复失败的操作。失败的等待将管道降级到生产者,失败的产量将管道降级到消费者。如果生产者未能让出或消费者未能等待,它们将被降级为基本 monad,它不能再失败。

消费者和生产者现在是不同的类型,并且没有暴露。它们与类型管道类型相同,只是缺少 Await 或 Yield 构造函数。这是必要的,至少对于生产者类型而言,因为管道没有可以禁止等待语句的输入类型。

Await 和 yield 语句默认终止作为它们的回退行为,这与之前的行为相同。Await 和 yield 将被分类以在支持它们的降级状态下工作。但是,一旦我们提出比 tryAwait 或 tryYield 更性感的名称,您现在可以选择提供自己的后备选项。

我仍然需要验证 Pipes 是否仍会使用此扩展名构成一个类别,但这似乎很有可能。它也是 100% 类型安全的,并使用类型来强制降级,而不是布尔值,并且程序员证明是不变的。

编辑:一些能激发你胃口的功能代码(从 gi​​thub 存储库中签出“try”分支以使用扩展):

printer = forever $ await >>= lift . print

take' n = replicateM_ n $ await >>= yield

fromList' = mapM_ (yieldOr (lift $ putStrLn "Undelivered elements))

diagnose = forever $ do
    x <- awaitOr (lift $ putStrLn "Await failed")
    yieldOr (lift $ putStrLn "Yield failed") x

> runPipe $ printer <+< take' 3 <+< diagnose <+< fromList [1..10]
1
2
3
Yield failed
Undelivered elements
> runPipe $ printer <+< take' 10 <+< diagnose <+< fromList [1..3]
1
2
3
Await failed
于 2012-02-05T01:45:22.390 回答
5

答案是肯定的。

使用 Hackage 上当前的管道实现,等待管道在其上游终止时立即终止。如果您使用该await函数,则受保护的管道也是如此。tryAwait如果您需要在终止前采取特殊行为,您只能选择使用。

此外,“受保护的管道”只是概念的一个临时名称,而我们正在制定集成其功能的最佳方式。我不认为他们会单独发布。

于 2012-02-05T01:44:50.487 回答