Haskell 中带有 monad 的表达式的结果
Result of expressions in Haskell with monads
我目前正在准备关于 Haskell 的期末考试,我正在复习 Monads,我们举了一个例子,例如:
给定 List Monad 的以下定义:
instance Monad [] where
m >>= f = concatMap f m
return x = [x]
其中 (>>=)
和 concatMap
的类型是
(>>=) :: [a] -> (a -> [b]) -> [b]
concatMap :: (a -> [b]) -> [a] -> [b]
表达式的结果是什么?
> [1,2,3] >>= \x -> [x..3] >>= \y -> return x
[1, 1, 1, 2, 2, 3] //Answer
这里的答案和我想的不一样,现在我们简要地回顾了 Monads,但据我了解 (>>=)
被称为 bind 并且可以在上面的表达式中读作 "applyMaybe".在这种情况下,对于绑定的第一部分,我们得到 [1,2,3,2,3,3]
并继续绑定的第二部分,但是 return x
被定义为 return x 的列表。应该是 [1,2,3,2,3,3]
。但是,我可能误解了这个表达。任何人都可以解释我的方法的错误做法以及我应该如何解决这个问题。谢谢。
首先,让我们弄清楚这个表达式是如何解析的:lambda 表达式是语法先驱,即它们尽可能多地抓住右边的东西,将其用作函数结果。所以你所拥有的被解析为
[1,2,3] >>= (\x -> ([x..3] >>= \y -> return x))
里面的表达式其实写的比应该写的复杂。 y
根本不用,a >>= \_ -> p
可以写成a >> p
。不过还有一个更好的替代方法:一般来说,monadic 绑定 a >>= \q -> return (f q)
等同于 fmap f a
,所以你的表达式应该写成
[1,2,3] >>= (\x -> (fmap (const x) [x..3]))
或
[1,2,3] >>= \x -> map (const x) [x..3]
或
[1,2,3] >>= \x -> replicate (3-x+1) x
此时应该很清楚结果是什么,因为列表 monad 中的 >>=
只是映射每个元素并连接结果。
this case for the first part of bind we get [1,2,3,2,3,3]
正确。
and we continue to the second part of the bind, but "return x" is defined to return the list of x. Which should have been [1,2,3,2,3,3].
请注意,在...
[1,2,3] >>= \x -> [x..3] >>= \y -> return x
... x
受第一个 (>>=)
(的 lambda)的约束,而不是第二个 (>>=)
的约束。一些额外的括号可能会使这一点更清楚:
[1,2,3] >>= (\x -> [x..3] >>= (\y -> return x))
在\y -> return x
中,y
绑定的值(即[1,2,3,2,3,3]
的元素)被忽略,取而代之的是x
绑定的相应值(即,生成每个 y
的原始列表的元素)。示意性地,我们有:
[1, 2, 3] -- [1,2,3]
[1,2,3, 2,3, 3] -- [1,2,3] >>= \x -> [x..3]
[1,1,1, 2,2, 3] -- [1,2,3] >>= \x -> [x..3] >>= \y -> return x
我目前正在准备关于 Haskell 的期末考试,我正在复习 Monads,我们举了一个例子,例如:
给定 List Monad 的以下定义:
instance Monad [] where
m >>= f = concatMap f m
return x = [x]
其中 (>>=)
和 concatMap
的类型是
(>>=) :: [a] -> (a -> [b]) -> [b]
concatMap :: (a -> [b]) -> [a] -> [b]
表达式的结果是什么?
> [1,2,3] >>= \x -> [x..3] >>= \y -> return x
[1, 1, 1, 2, 2, 3] //Answer
这里的答案和我想的不一样,现在我们简要地回顾了 Monads,但据我了解 (>>=)
被称为 bind 并且可以在上面的表达式中读作 "applyMaybe".在这种情况下,对于绑定的第一部分,我们得到 [1,2,3,2,3,3]
并继续绑定的第二部分,但是 return x
被定义为 return x 的列表。应该是 [1,2,3,2,3,3]
。但是,我可能误解了这个表达。任何人都可以解释我的方法的错误做法以及我应该如何解决这个问题。谢谢。
首先,让我们弄清楚这个表达式是如何解析的:lambda 表达式是语法先驱,即它们尽可能多地抓住右边的东西,将其用作函数结果。所以你所拥有的被解析为
[1,2,3] >>= (\x -> ([x..3] >>= \y -> return x))
里面的表达式其实写的比应该写的复杂。 y
根本不用,a >>= \_ -> p
可以写成a >> p
。不过还有一个更好的替代方法:一般来说,monadic 绑定 a >>= \q -> return (f q)
等同于 fmap f a
,所以你的表达式应该写成
[1,2,3] >>= (\x -> (fmap (const x) [x..3]))
或
[1,2,3] >>= \x -> map (const x) [x..3]
或
[1,2,3] >>= \x -> replicate (3-x+1) x
此时应该很清楚结果是什么,因为列表 monad 中的 >>=
只是映射每个元素并连接结果。
this case for the first part of bind we get [1,2,3,2,3,3]
正确。
and we continue to the second part of the bind, but "return x" is defined to return the list of x. Which should have been [1,2,3,2,3,3].
请注意,在...
[1,2,3] >>= \x -> [x..3] >>= \y -> return x
... x
受第一个 (>>=)
(的 lambda)的约束,而不是第二个 (>>=)
的约束。一些额外的括号可能会使这一点更清楚:
[1,2,3] >>= (\x -> [x..3] >>= (\y -> return x))
在\y -> return x
中,y
绑定的值(即[1,2,3,2,3,3]
的元素)被忽略,取而代之的是x
绑定的相应值(即,生成每个 y
的原始列表的元素)。示意性地,我们有:
[1, 2, 3] -- [1,2,3]
[1,2,3, 2,3, 3] -- [1,2,3] >>= \x -> [x..3]
[1,1,1, 2,2, 3] -- [1,2,3] >>= \x -> [x..3] >>= \y -> return x