Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type checking in If-then-else expressions

Tags:

haskell

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?

like image 636
MrBland Avatar asked Dec 13 '22 16:12

MrBland


1 Answers

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
like image 84
Daniel Wagner Avatar answered Jan 05 '23 00:01

Daniel Wagner