考虑此示例:
{-# 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
语句将从“ appliative do”中删除“ applicative”。为什么?
您希望将其糖化为什么样的应用表达?单子表达式是一系列链接的作用域,因此let
引入一个可扩展到所有其余作用域的绑定是有意义的,但是在适用的情况下,各个表达式不能真正相互依赖,因此没有作用域将let
糖化成糖是有意义的。
它将转换为
let unrelated = 1 in return $ Tuple x y'
不具有return <something>
形式,而适用requires the last statement to be a return
:
通常,do语句何时产生Monad约束的规则如下。如果do-expression具有以下形式:
return
其中p1 ... pn定义的变量均未在E1 ... En中提及,而p1 ... pn均为变量或惰性模式,则表达式只需要Applicative。否则,该表达式将需要Monad。该块可能会返回纯表达式E,具体取决于带有return或pure的结果p1 ... pn。
[如果您查看do p1 <- E1; ...; pn <- En; return E
中的删除修饰符的描述,它也完全不支持https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do。