什么是skolems?

Eeek! GHCi在我的代码中find了Skolems!

... Couldn't match type `k0' with `b' because type variable `b' would escape its scope This (rigid, skolem) type variable is bound by the type signature for groupBy :: Ord b => (a -> b) -> Set a -> Set (b, [a]) The following variables have types that mention k0 ... 

他们是什么? 他们想要什么与我的程序? 为什么他们试图逃脱(忘恩负义的小型拳击手)?

首先,上下文中的“刚性”typesvariables表示由该上下文之外的量词绑定的typesvariables,因此不能与其他typesvariables统一。

这很像一个lambda绑定的variables:给定一个lambda (\x -> ... ) ,从“外部”,当然可以将它应用于任何你喜欢的值。 但在内部,你不能简单地认定x的值应该是某个特定的值。 为lambda内的xselect一个值应该听起来很愚蠢,但这就是关于“无法匹配等等等等,刚性typesvariables,等等等等”的错误。

请注意,即使不使用显式全量量词,任何顶级types签名对于提到的每个typesvariables都有一个隐含的说明。

当然,这不是你得到的错误。 什么是“转义typesvariables”意味着更傻 – 这就像有一个lambda (\x -> ...)并尝试使用lambda 之外x具体值,独立于将其应用于参数。 不,不会将lambda应用于某些内容并使用结果值 – 我的意思是实际上使用variables本身在它所定义的范围之外。

这种情况可能发生在types上(没有像使用lambda的例子那样显然是荒谬的)是因为有两个“typesvariables”的概念是浮动的:在统一过程中,有“variables”代表未确定的types,然后被识别与其他这样的variables通过types推断。 另一方面,你有上面描述的量化typesvariables,这些variables具体被确定为可能的types。

考虑lambdaexpression式的types(\x -> x) 。 从一个完全不确定的typesa ,我们看到它只需要一个参数,把它缩小到a -> b ,那么我们就可以看到它必须返回与它的参数types相同的东西,所以我们把它进一步缩小到a -> a 。 但现在它适用于任何types,所以我们给它一个量词(forall a. a -> a)

所以,当你有一个量词的范围时,GHC推断应该与该量词范围之外的未确定types统一起来。


所以显然我忘了在这里解释“skolemtypesvariables”这个词,嘿。 正如评论中所提到的,在我们的例子中,它基本上是“刚性typesvariables”的同义词,所以上面仍然解释了这个想法。

我不完全确定这个术语是从哪里来的,但我猜想它涉及到Skolem的正常forms,并且代表了存在性的量化,就像在GHC中所做的那样。 skolem(或刚性)types的variables是在某个范围内由于某种原因具有未知但特定types的variables,它是来自存在性数据types&c的多态types的一部分。

据我所知,一个“Skolemvariables”是一个variables,它不匹配任何其他variables,包括它本身。

当你使用显式合并,GADT和其他types的系统扩展时,这似乎会在Haskell中popup。

例如,请考虑以下types:

 data AnyWidget = forall x. Widget x => AnyWidget x 

这说的是,你可以采取任何实现Widget类的types,并将其包装成AnyWidgettypes。 现在,假设你试图解开这个:

 unwrap (AnyWidget w) = w 

嗯,不,你不能这样做。 因为在编译时我们不知道w是什么types,所以没有办法为此写一个正确的types签名。 在这里, w的types已经从AnyWidget “逃脱”了,这是不允许的。

据我所知,内部GHC给出了一个types,这是一个Skolemvariables,来表示它不能逃脱的事实。 (这不是唯一的这种情况,还有其他一些地方,由于input问题,某些价值无法逃脱。

当一个typesvariables试图转义它的作用域时popup错误消息。

我花了一段时间才弄清楚这个,所以我会写一个例子。

 {-# LANGUAGE ExistentialQuantification #-} data I a = I a deriving (Show) data SomeI = forall a. MkSomeI (I a) 

那么如果我们尝试写一个函数

  unI (MkSomeI i) = i 

GHC拒绝types推断/types检查这个function。


为什么? 让我们尝试自己推断types:

  • unI是一个lambda定义,所以对于某些types的xy ,它的types是x -> y y
  • MkSomeI有一个types的forall a. I a -> SomeI forall a. I a -> SomeI
    • MkSomeI i有一个typesSomeI
    • iLHS有一个typesI ztypes。 由于所有的量词,我们不得不引入新的(新鲜的)types的variables。 请注意,这不是通用的,因为它被绑定在(SomeI i)expression式中。
    • 因此我们可以用SomeI统一typesvariablesx ,这是可以的。 所以unI应该inputSomeI -> y
  • iRHS上也有typesI z
  • 在这一点上,统一者试图统一yI z ,但是它注意到z是在较低的上下文中引入的。 因此它失败了。

否则, unI的types将会键入forall z. SomeI -> I z forall z. SomeI -> I z ,但是正确的是exists z. SomeI -> I z exists z. SomeI -> I z 。 然而,这个GHC不能直接表示。


同样,我们可以看到为什么

 data AnyEq = forall a. Eq a => AE a -- reflexive :: AnyEq -> Bool reflexive (AE x) = x == x 

作品。

AE x中的(存在variables)variables不会转移到外部范围内,所以一切正常。


另外我在GHC 7.8.4和7.10.1中遇到了一个“特征” ,其中RankNTypes本身是可以的,但是添加GADTs会触发错误

 {-# LANGUAGE RankNTypes #-} {-# LANGUAGE GADTs #-} example :: String -> I a -> String example str x = withContext xs where si = "Foo" ++ str withContext :: I a -> (forall b. I b -> c) -> c withContext xf = fx 

所以你的代码可能没有问题。 它可能是GHC,它不能一致地把所有东西都弄清楚。

编辑 :解决办法是给一个typess :: forall a. I a -> String s :: forall a. I a -> String

GADTs打开MonoLocalBinds ,这使得s推断types有skolemvariables,所以types不是全部forall a. I a -> String forall a. I a -> String ,但t -> String ,被绑定在错误的上下文。 请参阅: https : //ghc.haskell.org/trac/ghc/ticket/10644