haskell - 正确使用 do 表示法

标签 haskell monads

我正在尝试理解 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

如果我知道为什么上面的代码不起作用,我想我会更接近理解 Monadf 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 的函数至mb并返回 mb .

在这段代码中呢?
(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/

相关文章:

haskell - 映射类型级别列表

haskell - 这个语句中的类型是如何解析的

haskell - Haskell 在 2013 年有多重要?

haskell - 在 Haskell 中模拟交互的有状态对象

javascript - 尝试使用 LiveScript 理解 Maybe Monad

unit-testing - Haskell Test.Framework 指定从命令行运行的测试数量

haskell - 将 (0, 1] 更改为 (0, 1) 而不进行分支

haskell - (>>=) 的执行顺序不是我所期望的

database - 如何将数据库连接传递给我的 http 处理程序?

haskell - 混合任意一个或可能的单子(monad)