为什么 "let" 语句强制 "applicative do" 块需要 monad 约束?
Why does a "let" statement force an "applicative do" block into requiring a monad constraint?
考虑这个例子:
{-# 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
语句都会从 "applicative do" 中删除 "applicative"。为什么?
您想将此脱糖到什么应用表达式? monadic 表达式是一系列链式作用域,因此 let
引入一个扩展到所有剩余作用域的绑定是有意义的,但是对于 applicative 来说,各种表达式不能真正相互依赖,所以有没有将 let
脱糖到
有意义的范围
它将转化为
let unrelated = 1 in return $ Tuple x y'
没有 return <something>
的形式,应用 requires the last statement to be a return
or pure
:
In general, the rule for when a do statement incurs a Monad
constraint is as follows. If the do-expression has the following form:
do p1 <- E1; ...; pn <- En; return E
where none of the variables defined by p1...pn
are mentioned in E1...En
, and p1...pn
are all variables or lazy patterns, then the expression will only require Applicative
. Otherwise, the expression will require Monad
. The block may return a pure expression E
depending upon the results p1...pn
with either return
or pure
.
Note: the final statement must match one of these patterns exactly:
return E
return $ E
pure E
pure $ E
otherwise GHC cannot recognise it as a return statement, and the transformation to use <$>
that we saw above does not apply. In particular, slight variations such as return . Just $ x
or let x = e in return x
would not be recognised.
如果你看一下https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do中关于脱糖的描述,它也不支持let
任何方式。
考虑这个例子:
{-# 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
语句都会从 "applicative do" 中删除 "applicative"。为什么?
您想将此脱糖到什么应用表达式? monadic 表达式是一系列链式作用域,因此 let
引入一个扩展到所有剩余作用域的绑定是有意义的,但是对于 applicative 来说,各种表达式不能真正相互依赖,所以有没有将 let
脱糖到
它将转化为
let unrelated = 1 in return $ Tuple x y'
没有 return <something>
的形式,应用 requires the last statement to be a return
or pure
:
In general, the rule for when a do statement incurs a
Monad
constraint is as follows. If the do-expression has the following form:do p1 <- E1; ...; pn <- En; return E
where none of the variables defined by
p1...pn
are mentioned inE1...En
, andp1...pn
are all variables or lazy patterns, then the expression will only requireApplicative
. Otherwise, the expression will requireMonad
. The block may return a pure expressionE
depending upon the resultsp1...pn
with eitherreturn
orpure
.Note: the final statement must match one of these patterns exactly:
return E return $ E pure E pure $ E
otherwise GHC cannot recognise it as a return statement, and the transformation to use
<$>
that we saw above does not apply. In particular, slight variations such asreturn . Just $ x
orlet x = e in return x
would not be recognised.
如果你看一下https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do中关于脱糖的描述,它也不支持let
任何方式。