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

时间:2010-11-15 07:18:22

标签: syntax pattern-matching haskell

我正在尝试来自< 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'
-}

有什么想法吗?

1 个答案:

答案 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'
相关问题