首先,看一下“柯里·霍华德对应”,它指出计算机程序中的类型对应于直觉逻辑中的公式。直觉逻辑就像您在学校中学到的“常规”逻辑一样,但是没有排除中或双重否定法则的规律:
不是公理:P⇔¬P(但是P⇒¬P是可以的)
不是公理:P∨P
逻辑定律
您在遵循DeMorgan的定律的道路上是正确的,但是首先我们将使用它们来推导一些新的定律。DeMorgan法律的相关版本为:
- ∀x。P(x)=∃x ¬P(x)
- ∃x。P(x)=∀x ¬P(x)
我们可以得出(∀x。P⇒Q(x))= P⇒(∀x。Q(x)):
- (∀x.P⇒Q(x))
- (∀x.¬P∨Q(x))
- ¬P∨(∀x。Q(x))
- P⇒(∀x.Q)
并且(∀x。Q(x)⇒P)=(∃x。Q(x))⇒P(此在下面使用):
- (∀x。Q(x)⇒P)
- (∀x。¬Q(x)∨P)
- (¬∀x.¬Q(x))∨P
- (∃x。Q(x))∨P
- (∃x。Q(x))⇒P
请注意,这些定律也具有直觉逻辑。我们得出的两个定律在下面的论文中被引用。
简单类型
最简单的类型易于使用。例如:
data T = Con Int | Nil
构造函数和访问器具有以下类型签名:
Con :: Int -> T
Nil :: T
unCon :: T -> Int
unCon (Con x) = x
类型构造器
现在让我们解决类型构造器。采取以下数据定义:
data T a = Con a | Nil
这将创建两个构造函数,
Con :: a -> T a
Nil :: T a
当然,在Haskell中,类型变量是隐式通用量化的,因此它们实际上是:
Con :: ∀a. a -> T a
Nil :: ∀a. T a
访问器也同样容易:
unCon :: ∀a. T a -> a
unCon (Con x) = x
量化类型
让我们将现有量词∃添加到我们的原始类型中(第一个,没有类型构造函数)。与其在看起来不像逻辑的类型定义中引入它,不如在看起来像逻辑的构造函数/访问器定义中引入它。我们稍后将修复数据定义以进行匹配。
相反Int
,我们现在将使用∃x. t
。在这里,t
是某种类型的表达。
Con :: (∃x. t) -> T
unCon :: T -> (∃x. t)
根据逻辑规则(上面的第二个规则),我们可以将Con
to的类型重写为:
Con :: ∀x. t -> T
当我们将存在量词移到外部(prenex形式)时,它变成了通用量词。
因此,以下内容在理论上是等效的:
data T = Con (exists x. t) | Nil
data T = forall x. Con t | Nil
除非exists
在Haskell中没有语法。
在非直觉逻辑中,可以从以下类型得出以下内容unCon
:
unCon :: ∃ T -> t
之所以无效,是因为直觉逻辑中不允许进行这种转换。因此,不可能为unCon
没有exists
关键字而编写类型,并且不可能以prenex形式放置类型签名。很难保证类型检查器会在这种情况下终止,这就是Haskell不支持任意存在量词的原因。
资料来源
“具有类型推断的一流多态性”,Mark P. Jones,第24届ACM SIGPLAN-SIGACT编程语言原理研讨会论文集(web)