[英]Why does a “let” statement force an “applicative do” block into requiring a monad constraint?
Consider this example:考虑这个例子:
{-# 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'
Looks nice: But no:看起来不错:但没有:
[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.
Even this fails:即使这失败了:
instance Traversable (Tuple a) where
traverse f (Tuple x y) = do
y' <- f y
let unrelated = 1
return $ Tuple x y'
So, introducing any let
statement removes the "applicative" from the "applicative do" .因此,引入任何let
语句都会从"applicative do"中删除"applicative " 。 Why?为什么?
It would translate into它会转化为
let unrelated = 1 in return $ Tuple x y'
which doesn't have the form return <something>
, and applicative do requires the last statement to be a return
or pure
:它没有形式return <something>
,而 applicative do 要求最后一个语句是return
或pure
:
In general, the rule for when a do statement incurs a
Monad
constraint is as follows.一般而言,do 语句何时引发Monad
约束的规则如下。 If the do-expression has the following form:如果 do 表达式具有以下形式: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
.其中没有任何由p1...pn
定义的变量在E1...En
中被提及,并且p1...pn
都是变量或惰性模式,那么表达式将只需要Applicative
。 Otherwise, the expression will requireMonad
.否则,表达式将需要Monad
。 The block may return a pure expressionE
depending upon the resultsp1...pn
with eitherreturn
orpure
.该块可能会返回一个纯表达式E
取决于结果p1...pn
与return
或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.否则 GHC 无法将其识别为 return 语句,并且我们上面看到的使用<$>
的转换不适用。 In particular, slight variations such asreturn. Just $ x
特别是return. Just $ x
return. Just $ x
orlet x = e in return x
would not be recognised.return. Just $ x
或let x = e in return x
不会被识别。
If you look at the description of desugaring in https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do , it also doesn't support let
in any way.如果您查看https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do中的脱糖描述,它也不支持let
以任何方式。
What applicative expression would you like this to desugar to?你希望这个去糖的应用表达是什么? A monadic expression is a series of chained scopes, so it makes sense for a let
to introduce a binding that extends over all the remaining scopes, but with applicative the various expressions can't really depend on each other, so there's no scope that it makes sense to desugar the let
into. monadic 表达式是一系列链式作用域,因此let
引入一个扩展到所有剩余作用域的绑定是有意义的,但是通过应用程序,各种表达式不能真正相互依赖,所以它没有 scope对let
into 进行脱糖是有意义的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.