在开始学习Haskell之后,即使在阅读了大量文档之后,仍然有一些我在Haskell中无法理解的东西.
我知道要执行IO操作,你必须使用一个"IO monad",它将一个值包装在一种"黑盒子"中,这样任何使用IO monad的函数仍然是纯粹的功能.好的,很好,但那么IO操作实际发生在哪里?
这是否意味着Monad本身并不是纯粹的功能?或者是在C中实现IO操作,在Haskell编译器中"嵌入"?
我可以在纯Haskell中使用或不使用Monad编写可执行IO操作的内容吗?如果没有,如果在语言本身内部不可能,这种能力来自何处?如果它在Haskell编译器中嵌入/链接到C代码块,IO Monad最终会调用它来执行"脏工作"吗?
作为序言,IO
Monad
尽管有许多写得不好的介绍,但它不是"那个".它只是" IO
类型".monads没什么神奇之处.Haskell的Monad
课程是一件非常无聊的事情 - 它比大多数语言都支持的更加陌生和抽象.即使是工具,你也没有看到任何人称之为IO
"the 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
被调用的值main
,以及它使用的定义集合.编译器在生成代码时,会插入一个明确的非Haskell代码块,该代码块实际上在一个IO
值中运行效果序列.从某种意义上说,这就是Simon Peyton Jones(GHC的长期作者之一)在他的演讲中遇到的问题Haskell是没用的.
确实,无论实际执行IO动作,都不能保持概念纯粹.(并且有一个非常不纯的函数,它运行IO
在Haskell语言中暴露的动作.我不会说它比支持外部函数接口更多,并且使用它不正确会破坏你的程序非常糟糕.)但是Haskell的目的是为效果系统提供一个原则接口,并隐藏无原则的位.它以一种在实践中非常有用的方式实现.