我正在尝试理解 Monad,我有以下代码
f a b c d =
do one <- a + b
two <- c * d
three <- one + two
return three
以上编译
但是当我得到一个错误
*主> f 1 2 3 4
:1:1:
(Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0)) 没有实例
因使用“f”而产生
可能的修复:
添加实例声明
(Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0))
在表达式中:f 1 2 3 4
在“it”的等式中:it = f 1 2 3 4
:1:9:
(Num (a0 -> a0 -> t0)) 没有实例
源自文字“4”
可能的修复:
为 (Num (a0 -> a0 -> t0)) 添加实例声明
在`f'的第四个参数中,即`4'
在表达式中:f 1 2 3 4
在“it”的等式中:it = f 1 2 3 4
如果我知道为什么上面的代码不起作用,我想我会更接近理解 Monad
f 1 2 3 4
最佳答案
问题是您将包装的一元值与纯值混淆了。
首先要知道的是 do 表示法是常规函数调用的语法糖( >>=
和 >>
)。因此,这将有助于查看您的代码也脱糖。
让我们尝试一些更简单的东西
f a b =
do one <- a + b
return one
这与您的代码有相同的问题,但更简单。为了理解为什么它不起作用,我们问:这实际上意味着什么?好吧,我们可以重写
<-
使用 >>=
的符号 f a b = (a + b) >>= \x -> return x
(这不是最简单的表示,但说明了这一点)
如果您在 GHCi 中测试以下内容
>> :t (>>=)
Monad m => m a -> (a -> m b) -> m b
即函数
>>=
接受:m
类型的参数的 a
以及来自 a
的函数至m
的 b
并返回 m
的 b
.在这段代码中呢?
(a + b)
将是一个数字。
另一半怎么样
\x -> return x
采用
a
类型的对象并返回 m a
类型的对象对于任何 a
所以,你需要有一个数字,这也是某种单子(monad)。你能想到这样的事情吗?目前尚不清楚这将是什么,这是怀疑这应该进行类型检查的一个原因。
了解 monad 的一种好方法是看一些具体的例子。
Maybe
monad 表示可能失败的计算 instance Monad Maybe where
return = Just
(>>=) (Just a) f = f a
(>>=) Nothing _ = Nothing
这让你可以用类似的语气说话
f args = do x <- functionThatMightFail args
y <- anotherfunctionThatMightFail x
return y
或更简单的相同代码
f args = do x <- functionThatMightFail args
anotherfunctionThatMightFail x
也许
f args = functionThatMightFail args >>= anotherfunctionThatMightFail
另一方面,
List
monad 捕捉到对列表的每个元素执行相同功能,然后将结果连接在一起的想法。简单的例子比比皆是:f = do x <- [1,2,3,4]
[1..x]
如果您了解这些,请使用
State
单子(monad)。它可以帮助您了解“monad 是计算模型”这一更一般的概念。然后我会检查 Parsec,当然还有 IO
关于haskell - 正确使用 do 表示法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7962890/