8

In the Pipes Tutorial, it says that:

The concrete type synonyms use () to close unused inputs and X (the uninhabited type) to close unused outputs:

I'd like to understand why () and X are used the way they are. Why not X or () for both inputs and outputs?

4

2 回答 2

6

Xin pipe 通常Void在 Haskell 生态系统的其他部分拼写,所以让我们假装X = Void. 它是这样定义的:

data Void

它有一个“消除器”

absurd :: Void -> a
absurd x = case x of {}

如果你有某种类型的东西Void(并强制它),那么就出了问题。您的程序产生了错误,或者它陷入了无限循环。

使管道生产出任何类型的东西,而Void不是生产任何东西(合法的)。让它产生类型的东西()允许它产生东西,但是不携带信息的东西。它们基本上是时钟滴答声。

在输入端,一个消耗类型的东西的管道Void可以等待输入,但一旦它这样做,它就会卡住——没有人能够给它任何东西。消耗类型的东西的管道()可以等待,但只能获得时钟滴答声。

所有这些选择都是合理的。我怀疑 Gonzalez 希望类型系统能够防止用户意外地将纯生产者以错误的方式连接到纯消费者,并获得可能难以追踪的错误。通过让一个纯粹的生产者消费(),和一个纯粹的消费者生产Void,他不可能将它们以错误的方式连接起来。

于 2016-02-02T19:18:01.600 回答
3

这实际上是一个比管道更普遍的事情。()并且XHask类别(以及从Hask派生的类别)的初始和终端对象,这意味着对于所有 Haskell 类型a

  • 只存在一个态射a -> ()(即const ()
  • 只存在一个态射X -> a(即absurd)。

因此,任何函数链a -> ()>>>() -> b实际上不能依赖于左侧部分(因为a -> ()不携带任何信息),并且任何链a -> X>>>X -> b不能依赖于右侧部分。从这个意义上说,() -> b输入是关闭的,a -> X输出也是如此。

于 2016-02-02T19:42:57.580 回答