函数式编程:副作用究竟发生在哪里?
Functional programming : Where does the side effect actually happen?
开始学习Haskell后,虽然看了很多文档,但还是有一些不明白的地方Haskell
我知道要执行 IO 操作,您必须使用 "IO monad" 将值包装在一种 "black box" 中,因此使用 IO monad 的 any 函数仍然是纯函数。好的,好的,但是 IO 操作实际发生在哪里?
这是否意味着 Monad 本身不是纯函数式的?或者说IO操作是用C实现的,"embedded"在Haskell编译器里面?
我可以在纯 Haskell 中使用或不使用 Monad 来编写将执行 IO 操作的东西吗?如果不是,如果在语言本身内部不可能,这种能力从何而来?如果它是 Haskell 编译器内部的 embedded/linked 到 C 代码块,IO Monad 最终会调用它来执行 "dirty job" 吗?
作为序言,它不是 "the IO
Monad
",尽管很多 poorly-written 介绍都这么说。只是"the IO
type"。 monad 没有什么神奇之处。 Haskell 的 Monad
class 是一件非常无聊的事情——它只是不熟悉,比大多数语言可以支持的更抽象。你永远不会看到任何人调用 IO
"the IO
Alternative
,",即使 IO
实现了 Alternative
。过分关注 Monad
只会妨碍学习。
在纯语言中,原则性处理效果(不是side-effects!)的概念魔法是 IO
类型的存在。是真品。这不是一些标志说 "This is impure!"。它是完整的 Haskell 类型 * -> *
,就像 Maybe
或 []
。接受 IO 值作为参数的类型签名,如 IO a -> IO (Maybe a)
,是有意义的。带有嵌套 IO 的类型签名很有意义,例如 IO (IO a)
.
所以如果是实型,就一定有具体的含义。 Maybe a
作为类型表示类型 a
的 possibly-missing 值。 [a]
表示 0 个或多个 a
类型的值。 IO a
表示产生 a
.
类型值的一系列效果
请注意,IO
的全部目的是表示一系列效果。正如我上面所说,它们不是副作用。它们不能隐藏在程序的 innocuous-looking 叶中,并在其他代码背后神秘地更改内容。相反,效果是通过 IO
值这一事实而明确指出的。这就是为什么人们试图使用 IO
类型来最小化程序的一部分。你在那里做的越少,远距离的怪异动作干扰你的程序的方式就越少。
至于你的问题的主旨,那么 - 一个完整的 Haskell 程序是一个名为 main
的 IO
值,以及它使用的定义集合。编译器在生成代码时,会插入一个明确的 non-Haskell 代码块,该代码块实际运行 IO
值中的效果序列。从某种意义上说,这就是 Simon Peyton Jones(GHC long-time 的作者之一)在他的演讲 Haskell is useless.
中所表达的意思。
的确,任何实际执行IO 操作的东西都不能保持概念上的纯粹。 (还有那个运行 IO
操作的非常不纯的函数暴露在 Haskell 语言中。我不会多说它是为了支持外部函数接口而添加的,使用不当会严重破坏你的程序。)但是 Haskell 的要点是为效果系统提供一个有原则的接口,并隐藏无原则的位。它以一种在实践中非常有用的方式做到这一点。
开始学习Haskell后,虽然看了很多文档,但还是有一些不明白的地方Haskell
我知道要执行 IO 操作,您必须使用 "IO monad" 将值包装在一种 "black box" 中,因此使用 IO monad 的 any 函数仍然是纯函数。好的,好的,但是 IO 操作实际发生在哪里?
这是否意味着 Monad 本身不是纯函数式的?或者说IO操作是用C实现的,"embedded"在Haskell编译器里面?
我可以在纯 Haskell 中使用或不使用 Monad 来编写将执行 IO 操作的东西吗?如果不是,如果在语言本身内部不可能,这种能力从何而来?如果它是 Haskell 编译器内部的 embedded/linked 到 C 代码块,IO Monad 最终会调用它来执行 "dirty job" 吗?
作为序言,它不是 "the IO
Monad
",尽管很多 poorly-written 介绍都这么说。只是"the IO
type"。 monad 没有什么神奇之处。 Haskell 的 Monad
class 是一件非常无聊的事情——它只是不熟悉,比大多数语言可以支持的更抽象。你永远不会看到任何人调用 IO
"the IO
Alternative
,",即使 IO
实现了 Alternative
。过分关注 Monad
只会妨碍学习。
在纯语言中,原则性处理效果(不是side-effects!)的概念魔法是 IO
类型的存在。是真品。这不是一些标志说 "This is impure!"。它是完整的 Haskell 类型 * -> *
,就像 Maybe
或 []
。接受 IO 值作为参数的类型签名,如 IO a -> IO (Maybe a)
,是有意义的。带有嵌套 IO 的类型签名很有意义,例如 IO (IO a)
.
所以如果是实型,就一定有具体的含义。 Maybe a
作为类型表示类型 a
的 possibly-missing 值。 [a]
表示 0 个或多个 a
类型的值。 IO a
表示产生 a
.
请注意,IO
的全部目的是表示一系列效果。正如我上面所说,它们不是副作用。它们不能隐藏在程序的 innocuous-looking 叶中,并在其他代码背后神秘地更改内容。相反,效果是通过 IO
值这一事实而明确指出的。这就是为什么人们试图使用 IO
类型来最小化程序的一部分。你在那里做的越少,远距离的怪异动作干扰你的程序的方式就越少。
至于你的问题的主旨,那么 - 一个完整的 Haskell 程序是一个名为 main
的 IO
值,以及它使用的定义集合。编译器在生成代码时,会插入一个明确的 non-Haskell 代码块,该代码块实际运行 IO
值中的效果序列。从某种意义上说,这就是 Simon Peyton Jones(GHC long-time 的作者之一)在他的演讲 Haskell is useless.
的确,任何实际执行IO 操作的东西都不能保持概念上的纯粹。 (还有那个运行 IO
操作的非常不纯的函数暴露在 Haskell 语言中。我不会多说它是为了支持外部函数接口而添加的,使用不当会严重破坏你的程序。)但是 Haskell 的要点是为效果系统提供一个有原则的接口,并隐藏无原则的位。它以一种在实践中非常有用的方式做到这一点。