功能编程:副作用实际发生在哪里?

时间:2017-01-24 13:35:24

标签: haskell io functional-programming monads side-effects

在开始学习Haskell之后,即使在阅读了大量文档后,我仍然无法理解Haskell中的内容。

我理解为了执行IO操作,你必须使用一个“IO monad”,它将一个值包装在一种“黑盒子”中,所以使用IO monad的任何函数仍然是纯粹的功能。好的,没问题,但是IO操作实际发生在哪里了?

这是否意味着Monad本身并不是纯粹的功能?或者是在C中实现IO操作,在Haskell编译器中“嵌入”?

我可以在纯Haskell中使用或不使用Monad编写可执行IO操作的内容吗?如果没有,如果在语言本身内部不可能,这种能力来自何处?如果它在Haskell编译器中嵌入/链接到C代码块,IO Monad最终会调用它来执行“脏工作”吗?

1 个答案:

答案 0 :(得分:17)

作为序言,它不是IO Monad",尽管许多写得不好的介绍说。它只是" IO类型"。 monad没什么神奇之处。 Haskell的Monad课程是一件非常无聊的事情 - 它比大多数语言都支持的更陌生,更抽象。您还没有看到有人致电IO" IO Alternative,"即使IO实现了Alternative。过分关注Monad只会妨碍学习。

纯语言中原则处理效果(副作用!)的概念魔法是存在IO类型。这是一个真实的类型。它不是一些标语说"这是不纯的!"。它是完整的Haskell类型* -> *,就像Maybe[]一样。键入接受IO值作为参数的签名,如IO a -> IO (Maybe a),是有意义的。使用嵌套IO键入签名是有意义的,例如IO (IO a)

因此,如果它是一个真实的类型,它必须具有一个具体的含义。 Maybe a作为类型表示类型a可能缺失的值。 [a]表示0个或更多类型为a的值。 IO a表示生成类型为a的值的一系列效果。

请注意IO的整个目的是表示一系列效果。正如我上面所说,他们不是副作用。它们不能被隐藏在程序中看似无害的叶子中,并神秘地改变其他代码背后的东西。相反,效果相当明确地被称为IO值的事实。这就是人们尝试使用IO类型最小化其程序部分的原因。你在那里做的越少,远距离的幽灵行动干扰你的程序的方式就越少。

至于你问题的主旨,那么 - 一个完整的Haskell程序是一个名为IO的{​​{1}}值,以及它使用的定义集合。编译器在生成代码时,会插入一个明确的非Haskell代码块,该代码块实际运行main值中的效果序列。从某种意义上说,这就是Simon Peyton Jones(GHC的长期作者之一)在他的演讲Haskell is useless中得到的结论。

确实,无论实际执行IO动作,都不能保持概念纯粹。 (并且有一个非常不纯的函数,它运行在Haskell语言中暴露的IO个动作。我不会说它比支持外部函数接口更多,并且使用它不正确会破坏你的程序非常糟糕。)但Haskell的要点是为效果系统提供一个原则接口,并隐藏无原则的位。它以一种在实践中非常有用的方式实现。

相关问题