If-then-else表达式中的类型检查

4
我正在为解析器编写Monad实例,但在尝试实现bind时遇到了一些类型检查错误。以下代码未通过类型检查:
(=<<) :: (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报错称最后一行代码parse (f a) i期望类型为ParseResult b但实际接收到的类型是ParseResult a。然而,如果我删除错误检查代码,那么所有类型检查都能够正常通过:

f =<< p = P (\s -> let x = parse p s
                   in let (Result i a) = x
                      in parse (f a) i)

那么,是什么导致if-then-else表达式引起类型混淆呢?

1
这是有意义的,因为就我理解的代码而言,x 的类型是 a。因此,在第一个版本中,绑定可以返回 ParseResult a(在 then x 中)或者从 parse (f a) i 中返回 ParseResult b(来自parse (f a) i)。 - bartop
1个回答

12

比较:

data Boring a = Boring

doesn'tTypeCheck :: Boring a -> Boring b
doesn'tTypeCheck x = x

doesTypeCheck :: Boring a -> Boring b
doesTypeCheck Boring = Boring

你的情况类似:尽管你的错误结果 x 可能实际上并没有任何 a 值,但它的类型仍然标记为 a。你需要用 b 重新标记它。最简单的方法可能是从 if 切换到 case 语句,如下所示:

case parse p s of
    Error e {- :: ParseResult a -} -> Error e {- :: ParseResult b -}
    Result i a -> parse (f a) i

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接