为什么“ let”语句强制“ applyative do”块要求monad约束?

时间:2019-10-06 06:45:46

标签: haskell monads ghc applicative do-notation

考虑以下示例:

{-# language ApplicativeDo #-}

module X where

data Tuple a b = Tuple a b deriving Show

instance Functor (Tuple a) where
    fmap f (Tuple x y) = Tuple x (f y)

instance Foldable (Tuple a) where
    foldr f z (Tuple _ y) = f y z

instance Traversable (Tuple a) where
    traverse f (Tuple x y) = do
        y' <- f y
        let t' = Tuple x y'
        return $ t'

看起来不错!但是没有:

[1 of 1] Compiling X                ( X.hs, interpreted )

X.hs:15:9: error:
    • Could not deduce (Monad f) arising from a do statement
      from the context: Applicative f
        bound by the type signature for:
                   traverse :: forall (f :: * -> *) a1 b.
                               Applicative f =>
                               (a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
        at X.hs:14:5-12
      Possible fix:
        add (Monad f) to the context of
          the type signature for:
            traverse :: forall (f :: * -> *) a1 b.
                        Applicative f =>
                        (a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
    • In a stmt of a 'do' block: y' <- f y
      In the expression:
        do y' <- f y
           let t' = Tuple x y'
           return $ t'
      In an equation for ‘traverse’:
          traverse f (Tuple x y)
            = do y' <- f y
                 let t' = ...
                 return $ t'
   |
15 |         y' <- f y
   |         ^^^^^^^^^
Failed, no modules loaded.

即使失败了:

instance Traversable (Tuple a) where
    traverse f (Tuple x y) = do
        y' <- f y
        let unrelated = 1
        return $ Tuple x y'

因此,引入任何let语句将从“应用程序” 中删除“应用程序” 。为什么?

2 个答案:

答案 0 :(得分:5)

它将翻译为

let unrelated = 1 in return $ Tuple x y'

没有return <something>格式,而applicative则为requires the last statement to be a return or pure

  

通常,do语句何时受到Monad约束的规则如下。如果do-expression具有以下形式:

do p1 <- E1; ...; pn <- En; return E
     

p1...pn中没有提到E1...En定义的变量,而p1...pn都是变量或惰性模式,则表达式只需要Applicative。否则,表达式将需要Monad。该块可能会根据结果Ep1...pnreturn返回纯表达式pure

     

注意:最终声明必须与以下模式之一完全匹配:

return E
return $ E
pure E
pure $ E
     

否则,GHC无法将其识别为return语句,并且上面看到的使用<$>的转换也不适用。特别是,不会识别出诸如return . Just $ xlet x = e in return x之类的细微变化。

如果您在https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do中查看关于废止符号的说明,则它也不支持let

答案 1 :(得分:4)

您希望它对糖有什么作用?单子表达式是一系列链接的作用域,因此let引入一个可扩展到所有其余作用域的绑定是有意义的,但是在适用的情况下,各种表达式不能真正相互依赖,因此将let进行糖化处理没有任何意义。