Consider the following piece of code:
foo :: [Int]
foo = do
x <- [1..10]
if x < 5 then pure () else [] -- Control.Monad.guard (x < 5)
pure x
foo2 :: [Int]
foo2 =
[1..10] >>= \x ->
if x < 5 then pure x else [] >>= \y ->
pure y
In foo
, I have manually inlined Control.Monad.guard (x < 5)
, as noted in the comment.
Why does foo
compile, even though there is pure ()
in the code? How does the [()]
pass the type check? Is it a special case for the do syntax? If yes, is it described anywhere?
In foo2
, I attempted to "desugar" foo
without the do syntax. Note that there can't be any pure ()
, as it doesn't pass type checking.
I'm using ghc-8.8.4 if that's important.
You have several errors in your manual desugaring. One attempt that uses only >>=
would be:
foo2 :: [Int]
foo2 =
[1..10] >>= \x ->
(if x < 5 then pure () else []) >>= \_ ->
pure x
First, the parentheses are important: you're binding the result of the entire if
expression, not performing a bind inside of its else
branch. Second, you can't just introduce a new variable y
and then use it in your pure
result. Desugaring preserves the same expressions in your source code, it just moves them around a bit. So, pure x
must desugar to pure x
.
Hopefully you can see why this works: the type of ()
does not matter, because nobody ever looks at its value, and the result, pure x
, has the right type regardless.
But really GHC doesn't produce quite this code: x >>= \\_ -> y
is equivalent to x >> y
, and that's what's used for a statement in a do-block that does not bind its result to a variable. So really you get
foo2 :: [Int]
foo2 =
[1..10] >>= \x ->
(if x < 5 then pure () else []) >> pure x
And you can, if you prefer, use a slightly fancier operator from Functor to achieve the same result. Let's un-inline guard
, and use (<$) :: Functor f => a -> fb -> fa
instead of a monadic operation. x <$ y
is the same as y >> pure x
:
foo2 :: [Int]
foo2 =
[1..10] >>= \x ->
x <$ guard (x < 5)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.