我正在尝试来自< Real World Haskell>。
的代码在GHC版本6.10.4上:
data ParseState = ParseState {
string :: String
} deriving (Show)
newtype Parse a = Parse {
runParse :: ParseState -> Either String (a, ParseState)
}
parse :: Parse a -> String -> Either String a
parse parser initState =
case runParse parser (ParseState initState) of
Left err -> Left err
Right (result, _) -> Right result
一切顺利,直到我将'左错'改为'错误@(左_)':
-- err@(Left _) -> err
{-
- Occurs check: cannot construct the infinite type:
- a = (a, ParseState)
- When generalising the type(s) for `parse'
-}
有什么想法吗?
答案 0 :(得分:8)
这很微妙。 case
正在仔细检查Either String (a, ParseState)
类型的值,因此当您在
err@(Left _) -> err
err
具有相同的类型。但是,函数的返回类型表示它应该是Either String a
,它与err
的{{1}}类型不匹配。查看Either String (a, ParseState)
的类型:
Left
在
的右侧使用Left :: x -> Either x y
时
Left
您有机会选择其他Left err -> Left err
,即y
而不是a
。
因此,即使值相同,类型也不是,因此无法替换它们。
顺便说一句,(a, ParseState)
为您的案例提供了一些非常方便的功能(为了简单起见,专门针对Control.Arrow
):
(->)
其语义由自由定理修正(读:他们只有一个合理的实现,所以他们做你期望从他们的类型)。因此,您可以将代码编写为:
left :: (a -> a') -> Either a b -> Either a' b
right :: (b -> b') -> Either a b -> Either a b'
(+++) :: (a -> a') -> (b -> b') -> Either a b -> Either a' b'