Rigid / skolem 类型变量:可以作为参数但使用局部 where/let 语句转义范围

Rigid / skolem type variable: fine as parameter but escaping scope with local where/let statement

根据 What are skolems?,这有效:

{-# LANGUAGE ExistentialQuantification #-}

data AnyEq = forall a. Eq a => AE a

reflexive :: AnyEq -> Bool
reflexive (AE x) = x == x

但为什么不是这样:

reflexive2 :: AnyEq -> Bool
reflexive2 ae = x == x
  where
  AE x = ae

(或 let 的类似版本)。它产生的错误包括:

Couldn't match expected type ‘p’ with actual type ‘a’
        because type variable ‘a’ would escape its scope
      This (rigid, skolem) type variable is bound by
        a pattern with constructor: AE :: forall a. Eq a => a -> AnyEq,
        in a pattern binding
        at Skolem.hs:74:4-7

是否可以通过添加一些类型声明使其工作(有点像该问题中 withContext 示例的 s :: forall a. I a -> String 解决方案)。我觉得我想在某处添加一个Eq x

我(可能天真)对 reflexive 工作原理的理解如下:

我不明白为什么 reflexive2 不这样做,除了“单态限制”或“单态本地绑定”之类的东西,这有时会让事情变得很奇怪。我尝试使用 NoMonomorphismRestrictionNoMonoLocalBinds 的所有组合进行编译,但无济于事。

谢谢。

所以我想我找到了答案 in the documentation(所有地方!)。这说明:

  • 您不能在 let 或 where 绑定组中的存在量化构造函数上进行模式匹配
  • 这个限制的原因确实是一个实现
  • 我们会看到它有多烦人

还有一个request to lift the restriction(虽然看起来有点难度)

就我个人而言,现在我想我明白了,这并不那么烦人。但我确实认为生成的错误消息具有误导性(因为我不认为问题是范围泄漏),所以会要求更改它。 (如果生成的错误消息有对文档的引用,那也很好,所以也会通过询问来推动我的运气。)

感谢大家的评论,如果您认为我的观点有误,请告诉我。大卫.