为了澄清这个问题:它是关于 monad 类型类的优点(而不是没有统一类的实例)。
在阅读了许多引用资料后(见下文),
我得出的结论是,实际上,单子(monad)类 有没有解决的仅限 一,但大而关键 , 问题:具有上下文的类型上的函数“链接” .因此,著名的句子“单子(monad)是可编程的分号”。
事实上,一个monad可以看成an array of functions with helper operations .
我坚持单子(monad)之间的区别类(class) ,理解为其他类型的通用接口(interface);以及实例化类的这些其他类型(因此,“一元类型”)。
我知道 monad 类本身只能解决运算符的链接,因为主要是它只要求它的类型实例
拥有bind >>=
和 return
,并告诉我们他们必须如何表现。作为奖励,编译器极大地帮助了编码提供 do
monadic 类型的符号。
另一方面,
它是 每个 单个类型实例化 monad 类,解决 每个具体问题 , 但不仅仅是因为是 Monad 的一个实例.例如 Maybe
解决“函数如何返回值或错误”,State
解决了“如何使函数具有全局状态”,IO
解决“如何与外界交互”等问题。所有这些类都在上下文中封装了一个值。
但迟早,我们将需要对此类上下文类型进行链接操作。即,我们需要按特定顺序组织对这些类型的函数的调用(有关此类问题的示例,请阅读 You could have invented monads 中有关多值函数的示例)。
如果你让每种类型都是 monad 类的实例,你就解决了链接问题。
要使链接正常工作,您需要 >>=
只有它拥有的确切签名,没有其他。 (见 this question)。
因此,我猜下次您定义上下文数据类型 T 来解决问题时,如果您需要对函数的调用进行排序(在 T 的值上),请考虑将 T 设为 Monad
的实例。 (如果您需要“选择链接”并且可以从 do
符号中受益)。为了确保你做对了,检查 T 是否满足 monad laws
然后,我向 Haskell 专家提出两个问题:
引用
教程
StackOverflow 问答
最佳答案
你肯定是在用你所说的方式做一些事情——有很多事情Monad
意味着你已经很好地将它们分开了。
也就是说,我肯定会说链接操作不是 Monads 解决的主要问题。这可以使用普通的 Functor(有一些麻烦)或使用 Applicatives 轻松解决。 当“选择链接”时,您需要使用完整的 monad 规范。 尤其是Applicative
之间的紧张关系。和 Monad
来自 Applicative
需要静态了解副作用计算的整个结构。 Monad
可以在运行时更改该结构,从而牺牲一些可分析性来换取权力。
为了更清楚地说明这一点,您处理 Monad 但不是任何特定 monad 的唯一地方是,如果您定义的多态性限制为 Monad .这在 Control.Monad
中反复出现。模块,所以我们可以从那里检查一些例子。
sequence :: [m a] -> m [a]
forever :: m a -> m b
foldM :: (a -> b -> m a) -> a -> [b] -> m a
马上,我们可以扔掉
sequence
尤其是 Monad
因为Data.Traversable
中有对应的函数, sequenceA
它的类型比 Applicative f => [f a] -> f [a]
稍微通用.这应该是一个明确的指标, Monad
不是唯一的排序方式 .同样,我们可以定义
foreverA
如下foreverA :: Applicative f => f a -> f b
foreverA f = flip const <$> f <*> foreverA f
所以有更多的方法来排序非
Monad
类型。但是我们遇到了foldM
的麻烦。foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
foldM _ a [] = return a
foldM f a (x:xs) = f a x >>= \fax -> foldM f fax xs
如果我们尝试将这个定义翻译成
Applicative
我们可能会写的风格foldA :: (Applicative f) => (a -> b -> f a) -> a -> [b] -> f a
foldA _ a [] = pure a
foldA f a (x:xs) = foldA f <$> f a x <*> xs
但是 Haskell 会理所当然地提示这不会进行类型检查——每次递归调用
foldA
试图放置 f
的另一个“层”结果上。与 Monad
我们可以 join
那些层向下,但是Applicative
太弱了。那么这如何转化为
Applicative
限制我们选择运行时?嗯,这正是我们用 foldM
表达的意思。 ,一元计算(a -> b -> m a)
这取决于它的a
参数,来自先前一元计算的结果。这种事情在更纯粹的 Applicative
世界中根本没有任何意义。 .
关于haskell - 'Chaining operations' 是 Monad 类解决的 "only"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21261427/