什么是skolems?


69

eek!GHCi在我的代码中找到了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
...

这些是什么?他们想要我的程序什么?他们为什么要逃脱(忘恩负义的小家伙)?



是的,我看到了,但是那张票并没有太多解释什么是臭臭。
马特·芬威克

2
我正在寻找什么是skolem以及什么原因导致它们的解释,而不是具体如何解决我的代码。我已经解决了我的代码,但我真的不知道为什么我没有作出skolems走....
马特·芬威克

2
@MattFenwick如果您实际上可以显示产生类型错误消息的代码,则可以将其用作解释为什么出现Skolem变量的具体示例。
kosmikus 2012年

1
@MattFenwick:我相信这是GHC 6 vs. 7的问题,大约在两年前。
CA McCann 2012年

Answers:


54

首先,上下文中的“刚性”类型变量是指由该上下文外部的量词绑定的类型变量,因此无法与其他类型变量统一。

这非常像由lambda绑定的变量那样工作:给定lambda (\x -> ... ),您可以从“外部”将其应用于您喜欢的任何值;但在内部,您不能简单地确定的值x应为某个特定值。为xlambda内部选择一个值听起来很愚蠢,但这就是“无法匹配等等,刚性类型变量,等等等等”的错误。

请注意,即使不使用显式forall量词,任何顶级类型签名forall对于所提及的每个类型变量都具有隐式含义。

当然,这不是您得到的错误。“转义类型变量”的含义甚至更愚蠢-就像拥有一个lambda(\x -> ...)并尝试使用lambdax 之外的特定值,而与将其应用于参数无关。不,不将lambda应用于某些对象并使用结果值-我的意思是实际上在定义变量的范围之外使用变量本身

类型可能发生这种情况的原因(似乎不像使用lambda的示例那样荒谬)是因为存在两个“类型变量”概念:与其他此类变量通过类型推断。另一方面,您具有上述量化的类型变量,这些变量专门标识为可能的类型。

考虑lambda表达式的类型(\x -> x)。从一个完全不确定的类型开始a,我们看到它需要一个参数并将其范围缩小到a -> b,然后我们看到它必须返回与其参数相同类型的东西,因此我们将其进一步缩小到a -> a。但是现在它适用于a您可能需要的任何类型,因此我们给它一个数量词(forall a. a -> a)

因此,当您有一个由量词绑定的类型时,会发生转义的类型变量,GHC推断该变量应与该量词范围之外的未确定类型统一。


因此,显然我忘了在这里实际解释术语“ skolem类型变量”,嘿。正如评论中所提到的,在我们的例子中,它实际上是“刚性类型变量”的同义词,因此上面仍然解释了这个想法。

我不完全确定该术语的起源,但我想它涉及Skolem范式,并代表普遍性的存在性量化,就像在GHC中所做的那样。skolem(或刚性)类型变量是在某种范围内出于某种原因具有未知但特定的类型的变量-属于多态类型的一部分,来自存在数据类型&c。


9
..但是什么是skolem类型变量?
AndrewC 2012年

1
@AndrewC当我从SPJ的评论理解这里,“斯科伦” ==“刚性”,在此背景下。
Mikhail Glushenkov 2012年

@AndrewC:哈哈哈,我经历了所有这些解释,但是忘记了真正回到定义相关术语的过程。无论如何,正如米哈伊尔(Mikhail)所说,在这种情况下,它与“刚性”的含义相同。
CA McCann 2012年

2
斯科莱姆(Skolem)是与戈德尔(Goedel),教堂(Church),咖喱(Curry)等类似的当代逻辑学​​家
乔纳森·

23

据我了解,“ Skolem变量”是与任何其他变量(包括其自身)都不匹配的变量。

当您使用显式的forall,GADT和其他类型的系统扩展之类的功能时,这似乎在Haskell中弹出。

例如,考虑以下类型:

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

这说明您可以采用实现Widget该类的任何类型,并将其包装为一个AnyWidget类型。现在,假设您尝试解开包装

unwrap (AnyWidget w) = w

嗯,不,你不能那样做。因为在编译时我们不知道什么类型w,所以没有办法为此编写正确的类型签名。此处的类型w已从进行“转义” AnyWidget,这是不允许的。

据我了解,GHC在内部提供w了一个Skolem变量类型,以表示它不能逃逸的事实。(这不是唯一的这种情况;在其他几个地方,由于键入问题而无法逃逸某个值。)


23
我不同意“包括自身”。Skolem变量(或更好的Skolem常数)表示类型推断期间的未知固定类型。因此,Skolem常数确实与(统一)变量匹配,但与任何具体类型都不匹配。通常,Skolem常数确实是由存在性绑定产生的。它们与由通用绑定产生并与任何具体类型匹配的普通统一变量完全不同。
kosmikus 2012年

@kosmikus我绝对不是类型推断实际上如何工作的复杂专家。您的解释在逻辑上似乎是自洽的,所以...
MathematicalOrchid

4
kosmikus的观点通过如何data AnyEq = forall a. Eq a => AE a允许定义来证明reflexive (AE x) = x == x。调用==有效是因为x它与自身类型相同,即使我们不知道该类型是什么。
本·米尔伍德

在这种情况下,为什么展开类型不能为“ Widget x”?
egdmitry,2014年

2
@egdmitryWidget x不是类型-它是类型约束。如果输入的类型是unwrap :: Widget x => AnyWidget -> x“给定的AnyWidget,我可以把您要的任何可能的小部件交给您”。好吧,显然,此功能实际上无法做到这一点;它只能将原始包装的窗口小部件类型交给您。但是在编译时,我们不知道那是什么。因此,无法键入。
2014年

11

当类型变量试图转义其范围时,将弹出错误消息。

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

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

然后,如果我们尝试编写一个函数

 unI (MkSomeI i) = i

GHC拒绝对此功能进行类型推断/类型检查。


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

  • unI是lambda定义,因此它的类型适用x -> y于某些类型xy
  • MkSomeI 有一种 forall a. I a -> SomeI
    • MkSomeI i 有一种 SomeI
    • iLHS上有某种类型I z的某种类型z。由于forall量词的原因,我们不得不引入新的(新鲜)类型变量。注意,它不是通用的,因为它绑定在(SomeI i)表达式中。
    • 这样我们就可以用统一类型变量xSomeI。因此,unI应该具有type SomeI -> y
  • i因此在RHS上也有类型I z
  • 此时,unifier尝试统一yand I z,但是它注意到z在较低的上下文中引入了。因此它失败了。

否则的类型unI将具有类型forall 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不会逸出外部范围,因此一切正常。


我也遇到了GHC 7.8.4和7.10.1中的“功能”RankNTypes就其本身而言还可以,但是添加GADTs会触发错误

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}

example :: String -> I a -> String
example str x = withContext x s
  where
    s i = "Foo" ++ str

withContext :: I a -> (forall b. I b -> c) -> c
withContext x f = f x

因此,您的代码可能没有错。可能是GHC,它无法始终如一地解决所有问题。

编辑:解决方案是给s :: forall a. I a -> String

GADTs打开MonoLocalBinds,这使得推断类型的s有斯科伦变量,所以类型是不是forall a. I a -> String,但是t -> String,都t被束缚在错误的上下文。参见:https : //ghc.haskell.org/trac/ghc/ticket/10644

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.