用monad绑定函数写

时间:2017-08-10 06:20:45

标签: haskell

我有以下函数,用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结构。如何改进?

1 个答案:

答案 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的上下文中)