I am writing the Monad instance for a parser, and in trying to implement bind I am encountering some type checking errors. The following code does not type check:
(=<<) :: (a -> Parser b) -> Parser a -> Parser b
f =<< p = P (\s -> let x = parse p s
in if isErrorResult x
then x
else let (Result i a) = x
in parse (f a) i)
GHCi complains that the last line of code parse (f a) i
is expecting type ParseResult b
but received type ParseResult a
. However, if I remove the error checking code then everything type checks just fine:
f =<< p = P (\s -> let x = parse p s
in let (Result i a) = x
in parse (f a) i)
So what is it about the if-then-else expression that causes the type confusion?
Compare:
data Boring a = Boring
doesn'tTypeCheck :: Boring a -> Boring b
doesn'tTypeCheck x = x
doesTypeCheck :: Boring a -> Boring b
doesTypeCheck Boring = Boring
Your situation is analogous: though your error result x
probably doesn't actually have any a
values inside, its type is still tagged with a
. You'll need to "retag" it with b
. It's probably cleanest to do this by switching from if
to a case
statement, as in
case parse p s of
Error e {- :: ParseResult a -} -> Error e {- :: ParseResult b -}
Result i a -> parse (f a) i
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