我已经在一些地方宣读了使用ExistentialQuantification
可以获得与RankNTypes
相同的功能。有人可以举例说明为什么会这样或不可能?
答案 0 :(得分:10)
通常,Haskell中的所有类型变量都是在类型的最外层范围内隐式普遍量化的。 RankNTypes
允许通用量词forall
显示为嵌套,例如类型forall a b. (a -> a) -> b -> b
与forall b. (forall a. a -> a) -> b -> b
非常不同。
有一种感觉,功能箭头左侧的哪些类型在逻辑上“被否定”,与(->)
具有逻辑含义的意义大致相同。从逻辑上讲,通用和存在量词是由De Morgan二元性相关的:(∃x.P(x))等价于¬(∀x.¬P(x)),或换句话说“存在x这样的P(x)“对应于”并非如此,对于所有x,P(x)都是假的。“
因此,功能箭头左侧的“forall”被“否定”并且表现得像存在主义。如果你将整个事物放在另一个函数箭头的左边,它会被双重否定,并再次表现为一个通用的量词,模拟一些繁琐的细节。
同样的否定概念也适用于值,因此要对我们想要的类型exists x. x
进行编码:
forall x.
处于逆变(否定)位置x
的值。由于该值必须在量词的范围内,我们唯一的选择是双重否定 - 基本上是CPS变换。为避免限制其他内容,我们将对函数箭头右侧的类型进行普遍量化。因此exists x. x
已翻译为forall r. (forall x. x -> r) -> r
。将此处类型和量词的位置与上述要求进行比较,以验证其是否符合要求。
在更多操作方面,这仅仅意味着给定具有上述类型的函数,因为我们给它一个具有通用量化参数类型的函数,它可以将该函数应用于它喜欢的任何类型x
,并且因为没有其他方法可以获得r
类型的值,我们知道它会将该函数应用于某些。因此x
将引用某些类型,但我们不知道什么 - 这基本上是存在量化的本质。
在更实际的日常术语中,如果从功能类型的“另一侧”查看它,任何通用量化的类型变量都可以被视为存在的。因为作为类型推断的一部分执行的统一超出了量词范围,所以有时候最终会出现GHC必须将外部作用域中的类型变量与来自嵌套作用域的量化类型统一的情况,这就是编译器出错的方式关于逃避类型和skolems等等,后者(我假设)与Skolem normal form有关。
这与使用存在性的数据类型的关系是,虽然你可以声明这样的类型:
data Exists = forall a. Exists a
这代表一种存在主义类型,要获得“存在主义类型”,你需要通过模式匹配来解开它:
unexist :: Exists -> r
unexist (Exists x) = foo x
但是如果你考虑这个定义中foo
的类型是什么,你最终会得到像forall a. a -> r
这样的东西,它等同于上面的CPS样式编码。 CPS转换与数据类型的Church编码之间存在密切关系,因此CPS表单也可以看作模式匹配的具体版本。
最后,将事物与逻辑联系起来 - 因为那就是“存在量词”这个术语的来源 - 请注意,如果你认为被留下箭头作为否定而有点眯着眼睛忽略forall r. ...
CPS残余,这些存在类型的编码与作为起点的De Morgan二元化形式¬(∀x.¬P(x))完全相同。所以这些只是看待同一个概念的不同方式。
答案 1 :(得分:3)
我发现有些东西可以帮助理解C. A. McCann的观点,即函数箭头的左侧是“否定”是从game semantics的角度来看这个。例如,这里是一阶逻辑的非常简单的游戏语义(非常非正式地说明):
∀x.A
,对手选择t
我们玩A[x := t]
(A
,所有x
的免费实例都替换为t
})。A && B
,Opponent选择反对其中一个合取。not A
,玩家切换角色并玩A
。像这样的游戏的意义在于,如果玩家#1(最初的支持者)具有相应游戏的获胜策略,则命题在逻辑上是有效的,即,如果玩家#1具有获胜移动,则无论选择何种玩家# 2使。
请注意否定规则中的角色切换。该规则的效果应该是直观的。
由于命题与类型的对应关系,这可以转化为类型理论。让我们根据一些原子形成的类型重新制定游戏,∀
,类型变量,→
,⊤
和⊥
:
∀x.a
:对手选择一个原子P
,我们玩a[x := P]
(a
,x
的所有免费实例都替换为P
] a → b
:支持者选择是否反对a
(角色转换)或提议b
。⊤
有人居住,而⊥
则没有。)请注意,在a → b
的规则中,如果Proponent选择a
,则角色切换:初始Proponent必须成为a
的对手。这对应于箭头的左侧是“否定”的事实。 (我的想法是⊥ → b
无论b
是什么都有人居住,所以如果a → b
的支持者有一个反对a
的获胜策略,那么a → b
必须有人居住,所以它的支持者获胜。)
同样,我们的想法是,如果Runner有一个获胜策略,那么一种类型就会有人居住,而如果Crasher有一个获胜策略则无人居住。
游戏示例:∀r. (∀a. (a → Int) → a → r) → r
r := ⊥
:(∀a. (a → Int) → a → ⊥) → ⊥
∀a. (a → Int) → a → ⊥
a := String
:(String → Int) → String → ⊥
String → Int
Int
Int
有人居住; 支持者(亚军)获胜。假设我们为∃
添加了规则。规则必须是这样的:
∃x.a
:推荐人选择x := P
,我们玩a[x := P]
现在,我们可以通过分析相应的游戏树来分析McCann的∀r. (∀a. a → r) → r
相当于∃a.a
的断言。我不打算展示整个游戏树(或仔细证明等效性,真的),但我将展示两个说明性的游戏:
第一场比赛:∃a.a
a := ⊤
。⊤
有人居住; 支持者(亚军)获胜。第二场比赛:∀r. (∀a. a → r) → r
r := ⊥
:(∀a. a → ⊥) → ⊥
∀a. a → ⊥
a := ⊤
:⊤ → ⊥
⊤
或提议⊥
之间做出选择。现在,我要在这里进行的非正式观察是,在两个游戏中,Runner都是选择用于a
的类型的人。 ∃a.a
和∀r. (∀a. a → r) → r
之间的等价实际上归结为:没有策略允许Crasher成为选择a
的人。