我在互联网上搜索过,我找不到任何关于CHI的解释,这些解释不会迅速退化为逻辑理论的讲座,而这个讲座在我脑海中已经大大增加了。 (这些人说话就好像“直觉主义命题演算”是一个实际上对正常人来说意味着什么的短语!)
粗略地说,CHI说类型是定理,程序是那些定理的证明。但到底是什么意思意味着 ??
到目前为止,我已经想到了这一点:
考虑id :: x -> x
。它的类型说“鉴于X是真的,我们可以断定X是真的”。对我来说似乎是一个合理的定理。
现在考虑foo :: x -> y
。正如任何Haskell程序员都会告诉你的那样,这是不可能的。你不能写这个功能。 (好吧,无论如何都没有作弊。)作为一个定理,它说“假设任何X都是真的,我们可以得出结论,任何Y都是真的”。这显然是胡说八道。而且,当然,你不能写这个功能。
更一般地说,函数的参数可以被认为是“假定为真的”,结果类型可以被认为是“假设所有其他事物都是真的”。如果有一个函数参数,比如x -> y
,我们可以假设X为真意味着Y必须为真。
例如,(.) :: (y -> z) -> (x -> y) -> x -> z
可以被视为“假设Y暗示Z,X暗示Y,并且X为真,我们可以断定Z为真”。这对我来说在逻辑上是合理的。
现在,Int -> Int
到底意味着什么? O_O
我能想出的唯一明智的答案是:如果你有一个功能X - > Y - > Z,然后类型签名说“假设可以构造类型X的值,而另一个类型Y,则可以构造类型Z的值”。函数体将准确描述您将如何执行此操作。
这似乎有道理,但它不是很有趣。显然,它必须有更多......
答案 0 :(得分:43)
Curry-Howard同构简单地指出类型对应于命题,而值对应于证明。
Int -> Int
作为一个逻辑命题并不是真正有意义的。在将某些东西解释为逻辑命题时,您只对该类型是否居住(具有任何值)感兴趣。所以,Int -> Int
只是意味着“给定一个Int
,我可以给你一个Int
”,这当然是真的。它有许多不同的证据(对应于该类型的各种不同功能),但是当把它作为一个逻辑命题时,你并不在乎。
这并不意味着有趣的命题不能涉及这些功能;只是那种特殊的类型很无聊,作为一个命题。
对于不完全多态且具有逻辑意义的函数类型的实例,请考虑p -> Void
(对于某些 p ),其中Void
是无人居住的type:没有值的类型(除了⊥,在Haskell中,但我稍后会介绍)。获得Void
类型值的唯一方法是,如果你可以证明一个矛盾(当然,这是不可能的),并且因为Void
意味着你已经证明了一个矛盾,你可以得到任何它的价值(即存在一个函数absurd :: Void -> a
)。因此,p -> Void
对应于 p :这意味着“ p 意味着虚假”。
Intuitionistic logic只是普通函数式语言所对应的某种逻辑。重要的是,它是建设性的:基本上,a -> b
的证明为您提供算法来计算来自b
的{{1}},这不是'{1}}在常规经典逻辑中是真的(因为law of excluded middle,它会告诉你某些事情是真或假,但不是为什么)。
尽管像a
这样的函数并不像命题那样有意义,但我们可以用其他命题对它们进行陈述。例如,我们可以声明两种类型的相等类型(使用GADT):
Int -> Int
如果我们的值为data Equal a b where
Refl :: Equal a a
类型,那么Equal a b
与a
类型相同:b
对应命题 a = b 。问题是我们只能用这种方式谈论类型的相等性。但是,如果我们有dependent types,我们可以很容易地将此定义推广到任何值,因此Equal a b
将对应于值 a 和 b 是完全相同的。所以,例如,我们可以写:
Equal a b
此处, f 和 g 是常规函数,因此 f 可以很容易地具有类型type IsBijection (f :: a -> b) (g :: b -> a) =
forall x. Equal (f (g x)) (g (f x))
。再一次,Haskell不能这样做;你需要依赖类型来做这样的事情。
典型的函数式语言并不是非常适合编写证明,不仅因为它们缺少依赖类型,而且还因为⊥,对所有Int -> Int
类型a
起作用任何命题的证明。但total和Coq等Agda语言利用这些对应关系充当证明系统以及依赖类型的编程语言。
答案 1 :(得分:2)
理解意味着的最佳方式可能是使用类型作为命题和程序作为证据来启动(或尝试)。学习具有依赖类型的语言会更好,例如Agda(它用Haskell编写,类似于Haskell)。该语言有各种articles and courses。 Learn you an Agda不完整,但它试图简化事情,就像LYAHFGG一样。
以下是一个简单证据的示例:
{-# OPTIONS --without-K #-} -- we are consistent
module Equality where
-- Peano arithmetic.
--
-- ℕ-formation: ℕ is set.
--
-- ℕ-introduction: o ∈ ℕ,
-- a ∈ ℕ | (1 + a) ∈ ℕ.
--
data ℕ : Set where
o : ℕ
1+ : ℕ → ℕ
-- Axiom for _+_.
--
-- Form of ℕ-elimination.
--
infixl 6 _+_
_+_ : ℕ → ℕ → ℕ
o + m = m
1+ n + m = 1+ (n + m)
-- The identity type for ℕ.
--
infix 4 _≡_
data _≡_ (m : ℕ) : ℕ → Set where
refl : m ≡ m
-- Usefull property.
--
cong : {m n : ℕ} → m ≡ n → 1+ m ≡ 1+ n
cong refl = refl
-- Proof _of_ mathematical induction:
--
-- P 0, ∀ x. P x → P (1 + x) | ∀ x. P x.
--
ind : (P : ℕ → Set) → P o → (∀ n → P n → P (1+ n)) → ∀ n → P n
ind P P₀ _ o = P₀
ind P P₀ next (1+ n) = next n (ind P P₀ next n)
-- Associativity of addition using mathematical induction.
--
+-associative : (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-associative m n p = ind P P₀ is m
where
P : ℕ → Set
P i = (i + n) + p ≡ i + (n + p)
P₀ : P o
P₀ = refl
is : ∀ i → P i → P (1+ i)
is i Pi = cong Pi
-- Associativity of addition using (dependent) pattern matching.
--
+-associative′ : (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-associative′ o _ _ = refl
+-associative′ (1+ m) n p = cong (+-associative′ m n p)
在那里你可以看到(m + n) + p ≡ m + (n + p)
命题作为类型,它的证明作为函数。这种证明有更先进的技术(例如,preorder reasoning,Agda中的组合器就像Coq中的战术一样。)
还有什么可以证明:
head ∘ init ≡ head
用于向量,here。
您的编译器会生成一个程序,该程序的执行值与Coq中相同(主机)程序here的解释中获得的值相同。 This book也是关于语言建模和程序验证主题的好读物。
在建构性数学中可以证明的任何其他东西,因为Martin-Löf在其表达能力中的类型理论等同于ZFC。事实上,Curry-Howard同构可以扩展到physics and topology和algebraic topology。
答案 2 :(得分:2)
我能想出的唯一明智的答案是:如果你有一个功能X - > Y - > Z,然后类型签名说“假设可以构造类型X的值,而另一个类型Y,则可以构造类型Z的值”。函数体将准确描述您将如何执行此操作。这似乎有道理,但它不是很有趣。显然,它必须有更多......
嗯,是的,还有更多,因为它有很多含义,并提出了很多问题。
首先,您对CHI的讨论仅以蕴涵/函数类型(->
)为框架。你没有谈论这个,但你可能已经看到了分别对应于产品和总和类型的连接和分离。但是其他逻辑运算符如否定,通用量化和存在量化呢?我们如何将涉及这些的逻辑证据转化为程序?事实证明它大致是这样的:
id
确实具有类型forall a. a -> a
除此之外,它还意味着各种关于逻辑的证据立即转化为有关编程语言的证明。例如,直觉主义命题逻辑的可判定性意味着在简单类型的lambda演算中终止所有程序。
现在,Int到底是什么 - > Int意思是? O_O
这是一种类型,或者是一种命题。在f :: Int -> Int
中,(+1)
命名一个“程序”(在某种意义上,它将函数和常量都作为“程序”,或者作为证据。)语言的语义必须提供{{1 }}作为推理的原始规则,或证明f
如何是可以从这些规则和前提构建的证据。
这些规则通常根据定义类型基本成员的等式公理和规则来指定,这些规则允许您证明其他程序所属的类型。例如,从f
切换到Int
(从0向前的自然数),我们可以有这些规则:
Nat
(0 :: Nat
是0
)的原始证据Nat
x :: Nat ==> Succ x :: Nat
x :: Nat, y :: Nat ==> x + y :: Nat
x + Zero :: Nat ==> x :: Nat
这些规则足以证明关于自然数加法的许多定理。这些证明也将是程序。