由于模式变量而推断出的无限类型

infinite type inferred due to pattern variable

使用命名整个 case 表达式的模式变量会导致编译正确与错误 "An infinite type was inferred for an expression" 之间的区别。以下编译正确:

m = case Left "anything" of
  e@(Left err) -> Left err
  (Right f) -> case lookup "key" f of
    Nothing -> Left "something else"
    (Just x) -> Right x

但是,如果我们使用模式变量 e(用 e 代替 "Left err",功能等效),编译器会标记一个错误:

m = case Left "anything" of
  e@(Left err) -> e
  (Right f) -> case lookup "key" f of
    Nothing -> Left "something else"
    (Just x) -> Right x

"An infinite type was inferred for an expression: StrMap t1 while trying to match type t1 with type StrMap t1 while checking that expression case ((lookup "键") f) ...

我知道将 StrMap t1 与 t1 匹配是有问题的。我不明白为什么会这样。此外,在我的原始代码中,消息根本没有引用无限类型。以下是相关摘录:

retrieveDomeinResourceDefinition :: forall e.
  ResourceId
  -> Namespace
  -> (AsyncDomeinFile e (Either String PropDefs))
retrieveDomeinResourceDefinition id ns = do
  df <- retrieveDomeinFile (namespaceToDomeinFileName ns)
  case df of
    e@(Left err) -> pure $ e
    (Right f) -> case lookup id f of
      Nothing -> pure $ Left ("retrieveDomeinResourceDefinition: cannot find definition of " <> id <> " in DomeinFile for " <> ns)
      (Just propDefs) -> pure (Right propDefs)

retrieveDomeinFile :: forall e. Namespace -> AsyncDomeinFile e (Either String DomeinFile)

newtype PropDefs = PropDefs (StrMap Json)

现在编译器告诉我:"Could not match type: PropDefs with type StrMap PropDefs..." 编译器似乎没有注意到查找表达式。事实上,当我用 "pure (Right f)" 替换 "pure (Right propDefs)" 时,错误消失了(另一个出现在绑定 df 的行上,我理解)。

现在我写这篇文章,我注意到 'trying to match type t1 with type StrMap t1' 和 'could not match type: PropDefs with StrMap PropDefs' 之间的相似性。不过,我不明白为什么使用 e 会引入这个问题。

以这种方式使用模式匹配的值在功能上可能是等效的,但类型不是 - 类型系统没有证据表明 Right 的类型变量可以被忽略。

使用第二个示例中的类型 - 当您模式匹配 e@(Left err) 时,e 的类型将为 Either String DomeinFile - 但您需要 Either String PropDefs。模式匹配没有 "free up" 右边的类型变量,这就是为什么你必须重新构造 Left 的错误。