通过阅读有关不同 monad 的 Haskell 教科书章节,当作者从解释 bind 和 monad 法则的细节跳到实际使用 monad 时,我反复迷失了方向。突然,诸如“在 monadic 上下文中运行函数”或“运行 monad”之类的表达出现了。同样,在库文档和关于 monad 转换器堆栈的讨论中,我读到一些函数“可以在任何选择的 monad 中运行”的声明。这个“在 monad 中运行”到底是什么意思?
有两件事我似乎没有弄清楚:
return
, >>=
)和法律的类型类。因此,在 monad 中“运行”某些东西可能意味着 (a) 将其作为参数提供给 return
。 , 或 (b) 使用 >>=
对其进行排序.如果 monad 的类型为 m a
, 那么如果 a) 某些东西的类型必须是 a
, 以匹配 return
的类型功能。如果 b) 某些东西必须是 a -> m b
类型的函数, 以匹配 >>=
的类型功能。由此,我不明白如何在任意 monad 中“运行”某些函数,因为我使用 >>=
对函数进行排序必须都具有相同的类型签名,并且我使用 return
提升的值必须是特定的 monad 类型参数。 run
函数如 runReader
, runState
等。这些函数不是 monad 定义的一部分,它们是普通函数,在语言的功能核心之外,无论如何都不是特殊的命令式语句。那么,他们“跑”的是什么? 我觉得清楚地理解这些概念是理解 monad 转换器堆栈或类似结构的关键,这些结构似乎对于理解 Haskell 中的任何实质性库和任何非平凡程序都是必要的。非常感谢您帮助我实现了从简单编写功能代码到真正理解其含义的飞跃。
最佳答案
撰写书籍和文章的作者在尝试解释概念时经常使用隐喻和不太精确的语言。目的是让读者对正在发生的事情有一个概念上的直觉。
我相信“运行”函数的概念属于这一类。除了 IO
,你是对的,你用来组成的函数,比如说,[]
, Maybe
等与其他功能没有什么特别之处。
我认为,在 monad 中运行某些东西的概念来自于 functors are containers 的观察。 .这个观察也适用于单子(monad),因为所有单子(monad)都是仿函数。 [Bool]
是一个 bool 值容器,Maybe Int
是(零或一)数字的容器。你甚至可以想到阅读器仿函数 r -> a
作为 a
的容器值,因为您可以想象它只是一个非常大的查找表。
能够“在容器内运行函数”很有用,因为并非所有容器都可以访问其内容。再次,IO
是最好的例子,因为它是一个不透明的容器。
一个常见问题是:How to return a pure value from a impure method .同样,许多初学者问:我如何获得 Maybe
的值? ?你甚至可以问:我如何从列表中获取值(value)?概括地说,问题变成:How to get the value out of the monad .
答案是你没有。你'在容器内运行函数',或者,正如我喜欢说的,你 inject the behaviour into the monad .你永远不会离开容器,而是让你的函数在它的上下文中执行。特别是当涉及到 IO
时,这是您可以与该容器交互的唯一方式,因为它是不透明的(我在这里假装 unsafePerformIO
不存在)。
请记住,当涉及到绑定(bind)方法( >>=
)时,虽然“在其中运行”的函数具有类型 a -> m b
,您也可以“运行”一个“正常”函数a -> b
使用 fmap
在 monad 内, 因为所有 Monad
实例也是 Functor
实例。
关于haskell - monad 中的 "run"是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61814313/