保护管道的行为与使用等待的管道相同吗?

时间:2012-02-04 23:43:57

标签: haskell iterate

Pipes是一个非常优雅,非常简单的迭代版本。您可以使用原语awaityield轻松编写管道代码。 Paolo Capriotti使用guarded pipes扩展了管道的概念,它使用稍微复杂的tryAwait原语,允许管道在输入流用完后执行一些最终化。

受保护的管道实施根据await

重新定义tryAwait
await = tryAwait >>= maybe discard return

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

2 个答案:

答案 0 :(得分:11)

这是发布Pipes的Gabriel。我一直在与Paolo合作,我们在工作中有一个更优雅的实现,比他原来的提议更强大,更安全。对你的问题的简短回答是,最终的实现是原始Pipes的超集,你可以用相同的行为和语义编写与以前相同的代码。

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

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

Await和yield语句默认为终止作为其后退行为,这与以前的行为相同。等待和收益率将被用于支持它们的降级州。但是,只要我们提出比tryAwait或tryYield更性感的名称,您现在可以选择提供自己的后备。

我还必须验证Pipes仍然是这个扩展名的类别,但似乎很可能。它也是100%类型安全,并使用类型来强制降级而不是布尔值和程序员证明不变。

编辑:一些有用的代码来激发你的胃口(从github存储库中检出“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

答案 1 :(得分:5)

答案是肯定的。

随着Hackage上当前管道的实现,等待管道在其上游终止时立即终止。如果使用await函数,保护管道也是如此。如果您需要在终止前特别表现,您可以选择使用tryAwait

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