'err @(Left _)'和'left err'之间有什么区别?

aXq*_*Xqd 3 syntax haskell pattern-matching

我正在尝试<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
Run Code Online (Sandbox Code Playgroud)

一切顺利,直到我将'Left err'改为'err @(Left _)':

--  err@(Left _)      -> err
{-
 -  Occurs check: cannot construct the infinite type:
 -    a = (a, ParseState)
 -  When generalising the type(s) for `parse'
-}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

luq*_*qui 8

这很微妙.将case被审议类型的值Either String (a, ParseState),所以当你的名字在模式

err@(Left _) -> err
Run Code Online (Sandbox Code Playgroud)

err有相同的类型.但是,函数的返回类型表示它应该是a Either String a,它err的类型不匹配Either String (a, ParseState).看看的类型Left:

Left :: x -> Either x y
Run Code Online (Sandbox Code Playgroud)

当您Left在右侧使用时

Left err -> Left err
Run Code Online (Sandbox Code Playgroud)

你给它一个选择不同的机会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'
Run Code Online (Sandbox Code Playgroud)

其语义由自由定理修正(读:它们只有一个合理的实现,因此它们按照你的类型做你所期望的).所以你可以编写你的代码:

parse parser = right fst . runParse parser . ParseState
Run Code Online (Sandbox Code Playgroud)