I'm a very new Haskell learner. I have a working expression:
do x <- try parseA <|> parseB
return x
which appears to work perfectly (I'm using the Parsec
package, but I hope this question has nothing to do with its functionality, as far as I know <|>
is a Parsec-defined infix operator). parseA
and parseB
both have the Parser Foo
monad type, as does the whole expression.
Based on what I've read so far, it seems this should be equivalent to
do return (try parseA <|> parseB)
and
do return $ try parseA <|> parseB
but none of the latter compile, they complain of mismatched types (errors below).
My other attempt to rewrite this, as
(try parseA <|> parse B) >>= return
seems to work. But if I've misunderstood this too, please say.
So my question is, can someone explain why the first three are different. I'm confused why they aren't equivalent. What am I missing?
Errors (in case this is relevant, though fwiw I'm not looking to 'fix' my code - I have a working version, I'm looking to understand how the versions differ):
do return (try parseA <|> parseB)
gives
parse.hs:76:11:
Couldn't match expected type ‘Foo’
with actual type ‘Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo’
and
do return $ try parseA <|> parseB
gives
parse.hs:76:3:
Couldn't match type ‘Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo’
with ‘Foo’
Expected type: Parser Foo
Actual type: Text.Parsec.Prim.ParsecT
String
()
Data.Functor.Identity.Identity
(Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo)
You should verify with a Haskell grammar specification. – Mateen Ulhaq. Jul 28, 2020 at 23:35. 3. An expression is any piece of code that results in a value (e.g. 8 or 1+1 or \x -> x*2 ).
It is important to know that let ... in ... is an expression, that is, it can be written wherever expressions are allowed. In contrast, where is bound to a surrounding syntactic construct, like the pattern matching line of a function definition.
Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).
The rules for do notation desugaring imply that
do x <- try parseA <|> parseB
return x
is equivalent to
(try parseA <|> parse B) >>= return
($)
versus (>>=)
Since (=<<)
is a flipped version of (>>=)
, both are equivalent to
return =<< (try parseA <|> parse B)
This implies that the only difference between your correct version and return $ try parseA <|> parse B
is the difference between (=<<)
and ($)
, whose types are:
($) :: (a -> b) -> a -> b
(=<<) :: (a -> m b) -> m a -> m b
You can see that ($)
is not a replacement for (=<<)
, but perhaps you can also see that they are somewhat similar. One way to look at it is that (=<<)
– and thus also (>>=)
– is a kind of function application that applies "monadic functions" of type a -> m b
for some Monad m
to "monadic values" of type m a
for some Monad m
, whereas ($)
is the usual kind of function application that applies functions of type a -> b
to values of type a
.
One of the monad laws is that
k >>= return = k
This implies that
(try parseA <|> parse B) >>= return
can also be written as
try parseA <|> parse B
which means your original form using do notation can also be written that way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With