我有以下函数,用do
语句写成:
l2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
l2 f a b = do
x <- a
y <- b
return (f x y)
do
语句是>>=
的糖,所以我尝试用运算符编写它:
l2' :: Monad m => (a -> b -> c) -> m a -> m b -> m c
l2' f a b = a >>= (\x -> b >>= (\y -> f x y))
并且编译器抱怨:
D:\haskell\chapter18\src\ExerciseMonad.hs:159:41: error:
* Couldn't match expected type `m c' with actual type `c'
`c' is a rigid type variable bound by
the type signature for:
l2' :: forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> m a -> m b -> m c
at D:\haskell\chapter18\src\ExerciseMonad.hs:158:10
* In the expression: f x y
In the second argument of `(>>=)', namely `(\ y -> f x y)'
In the expression: b >>= (\ y -> f x y)
* Relevant bindings include
b :: m b
(bound at D:\haskell\chapter18\src\ExerciseMonad.hs:159:11)
a :: m a (bound at D:\haskell\chapter18\src\ExerciseMonad.hs:159:9)
f :: a -> b -> c
(bound at D:\haskell\chapter18\src\ExerciseMonad.hs:159:7)
l2' :: (a -> b -> c) -> m a -> m b -> m c
(bound at D:\haskell\chapter18\src\ExerciseMonad.hs:159:3)
因为f
的返回值不是monadic结构。如何改进?
答案 0 :(得分:4)
您忘记在return
周围添加f x y
。让我们来看看如何去除do
:
do --
x <- foo -- foo >>= (\x ->
bar -- bar >>
foobar x -- foobar x)
请注意,我们没有删除任何内容。我们只是切换箭头并添加bind
,如果你想这样读它。如果我们遵循这种方法,我们可以等效地解决您的代码:
do --
x <- a -- a >>= (\x ->
y <- b -- b >>= (\y ->
return (f x y) -- return (f x y)))
return
停留。它不是do
糖的一部分。因此,我们最终
l2' f a b = a >>= (\x -> b >>= (\y -> return (f x y)))
备注:只要您的实例遵循monad和适用法律,您就不需要Monad
来实施l2'
。您可以改为使用Applicative
:
l2' f a b = f <$> a <*> b
练习:如果您还不知道Applicative
,请尝试猜测<$>
和<*>
类型可能是什么(在Monad
的上下文中) 子>