15

输出是一种有效的计算。因此,将其封装到 monad 中是有意义的。但是输入是上下文相关的计算。因此,将它封装成一个comonad 会更有意义。

但是在 Haskell 中,输入和输出都封装在IOmonad 中。为什么?

4

2 回答 2

18

一个comonad 有一个extract :: w a -> a方法,不能(合理地)为IO.

输入在comonad 的意义上不是真正的上下文敏感的。comonad 的“上下文敏感性”意味着它对数据结构中更大的上下文敏感。例如,列表拉链就像一个列表,在任何给定时刻,列表中都有一些关于“我们在哪里”的额外位置信息。数据结构实际上并没有任何实际结构IO,因此它没有敏感的上下文。

该结构允许我们使用操作Monad从类型内部访问输入,所以一切正常。IO>>=

另外,请注意,术语“有效”和“上下文敏感”有点非正式,因此,对于单子和共子的所有示例可能并不完全有意义:函数 monad 真的“有效”吗?comonad(,) e真的是“上下文敏感的”吗?

顺便说一句,培养对单子和共单子如何工作的直觉的最好方法是通过使用它们来获得经验(这也适用于许多其他事情)。不幸的是,没有一个很好的方法可以用“有效”或“上下文敏感”这样的短语来总结它们,从而让您了解它们的实际工作方式。这些短语可以帮助一些人,但重要的是要记住它们的局限性。

此外,理解类型类的最佳方法是理解它的实例(尝试浏览所有提供的实例并找出它们)。完成此操作后,您可以查看类型类如何连接到所有这些。这将使您对类型类的“含义”有一个很好的直觉。我还应该指出,在处理类型类的实例时(至少)将可能为类型类提供的任何法律保留在您的脑海中是一个好主意。

于 2014-08-05T20:47:29.420 回答
5

comonad 的签名extract :: w a -> a意味着我们可以a用纯计算进行计算,没有任何副作用。

另一方面,IO当我们想使用副作用产生一些价值时,我们会使用它。即使是看起来只需要输入的东西也有副作用。例如:通过网络接收数据,从文件中读取字节并推进流位置,从数据库中读取数据可能会产生副作用,例如打开网络连接、记录访问、激活某些触发器等。所以comonad 不是的适当抽象IO

于 2014-08-06T14:13:07.110 回答