类型检查器的正确性证明实际上应该证明什么?


11

我已经进行了几年编程,但是对理论CS并不熟悉。我最近一直在尝试学习编程语言,并且其中的一部分是类型检查和推断。

我的问题是,如果我尝试为一种编程语言编写类型推断和检查程序,并且希望证明我的类型检查器可以工作,那么我要寻找的证明到底是什么?

用通俗易懂的语言,我希望类型检查器能够识别出在运行时可能发生的代码中的任何错误。如果我要使用类似Coq的方法来证明我的实现是正确的,那么这种“正确性证明”将试图显示什么?


也许您可以澄清一下,是否想知道(1)您的实现是否确实实现了给定的键入系统,或(2)您的键入系统是否确实阻止了您认为应该的错误?他们是不同的问题。TT
Martin Berger

1
@MartinBerger:啊,我似乎跳过了那个区别。我的实际问题可能是要问两个。上下文是我正在尝试构建一种语言,为此我正在编写一个类型检查器。人们要求我使用经过验证的算法。我对“证明”所使用的算法和类型检查器“正确”有多难。因此,我的问题含糊不清。
Vivek Ghaisas

2
(1)确实是程序验证中的一个问题,与键入无关。只需显示您的实现符合其规范即可。对于(2),首先定义立即类型错误的含义(例如,类似2 + "hello"“卡住”的术语)。一旦形式化,您就可以证明类型健全性定理。这意味着没有可打字的程序可以演变成立即类型错误。正式地,您证明如果程序是可键入的,并且对于任何:如果运行步成为,则没有立即类型错误。(1/2)MnMnNN
Martin Berger

1
这通常通过对和分型程度的推导来证明。(2/2)n
马丁·伯杰

谢谢!根据您的解释,似乎(2)确实是我想要的。你能给个答案吗?(也许添加您认为有用的任何细节。)我会接受这作为答案!:)
Vivek Ghaisas

Answers:


10

这个问题可以用两种方式解释:

  • 该实现是否实现了给定的键入系统?T
  • 打字系统是否确实可以防止您认为应该的错误?T

前者确实是程序验证中的一个问题,与键入无关。只需显示您的实现符合其规范,请参阅Andrej的答案。

让我谈谈后面的问题。正如安德烈(Andrej)所说,从抽象的角度来看,键入系统似乎在程序上强制执行属性。实际上,您的键入系统试图防止发生错误,这意味着可键入程序不应表现出感兴趣的错误类别。为了表明做了您认为应该做的事情,您必须做两件事。TT

  • 首先,您正式定义程序立即输入错误的含义 。可以通过多种方式定义它-由您决定。通常,我们要阻止类似的程序 2 + "hello"。换句话说,您需要定义一个程序子集,将它们称为 Bad,它完全包含具有立即输入错误的程序。

  • 然后,您必须证明可打字的程序永远不会演变成Bad程序。让我们对此进行形式化。让您的打字判断为 回想一下,应将其读取为:程序 类型为,假定自由变量的类型由环境。那么您要证明的定理是:ΓM:α.MαΓ

    定理。每当和然后 BadΓM:αMNN

    如何证明该定理取决于语言的细节,键入系统以及您对Bad的选择。

定义Bad的一种标准方法是说:术语如果既不是值也不是归约步骤,则具有立即类型错误。(在这种情况下,通常称为“ 卡住”。)这仅适用于小步操作语义。证明定理的一种标准方法是证明MMNM

  • ΓM:α和一起表示。这称为“主体减少”。通常通过同时归纳打字判断的推导和减少的时间来证明。MNΓN:α

  • 每当 然后不。通常也可以通过归纳打字判断来证明这一点。ΓM:αM

请注意,并非所有键入系统都具有“主题缩减”功能,例如会话类型。在这种情况下,需要更复杂的证明技术。


20

这是个好问题!它询问我们对键入语言中的类型的期望。

首先请注意,我们可以使用unitype键入任何编程语言:只需说一个字母U,然后说每个程序都具有type即可U。这不是非常有用,但是很有意义。

有很多理解类型的方法,但是从程序员的角度来看,我认为以下内容很有用。将类型视为规范保证。说具有类型就是说“我们保证/期望/要求满足由编码的属性”。通常,就像一样简单,在这种情况下,属性只是“它是整数”。eAeAAint

您的类型的表达能力没有止境。原则上,它们可以是任何种类的逻辑语句,也可以使用类别理论和诸如此类的东西。例如,从属类型将使您可以表达诸如“此函数将列表映射到列表以使输出为排序的输入”之类的内容。您可以走得更远,此刻,我正在听有关“并行分离逻辑”的演讲,该演讲使您可以谈论并发程序如何在共享状态下工作。花哨的东西。

编程语言设计中的类型艺术是表达性和简单性之间的一种平衡

  • 更具表现力的类型使我们能够(对自己和对编译器)更详细地解释应该发生的情况
  • 简单类型更易于理解,并且可以在编译器中更轻松地实现自动化。(人们提出的类型本质上需要证明助手和用户输入来进行类型检查。)

不应低估简单性,因为并非每个程序员都拥有编程语言理论的博士学位。

因此,让我们回到您的问题:您怎么知道您的类型系统是好的?好吧,证明定理可以证明您的类型是平衡的。有两种定理:

  1. 定理说你的类型是有用的。知道程序具有类型应该暗示一些保证,例如,程序不会卡住(这将是安全性定理)。另一类定理会将类型与语义模型联系起来,以便我们可以开始使用实数数学来证明有关程序的信息(这些将是适当性定理,以及许多其他定理)。上面的单型不好,因为它没有这么有用的定理。

  2. 定理说你的类型很简单。一个基本的判断是,给定表达式是否具有给定类型是可以确定的。另一个简单功能是提供一种推断类型的算法。关于简单性的其他定理是:表达式最多具有一种类型,或者表达式具有主体类型(即,它具有的所有类型中的“最佳”类型)。

由于类型是非常通用的机制,因此很难更具体。但是,我希望您能看到应该射击的东西。像编程语言设计的大多数方面一样,也没有绝对的成功衡量标准。取而代之的是存在设计可能性的空间,而重要的是要了解您在空间中或想要在空间中的位置。


谢谢您的详细回答!但是,我仍然不确定我的问题的答案。作为一个具体示例,让我们以C-具有足够简单的类型系统的静态类型语言为例。如果我为C编写了一个类型检查器,如何证明我的类型检查器是“正确的”?如果我改为为Haskell写类型检查器,这个答案将如何改变?我现在将如何证明“正确性”?
Vivek Ghaisas

1
1.实际上将C 的类型系统定义为一个数学实体(以便可以证明有关它的定理)。2.实现您的类型检查器,或描述一种用于类型检查的算法。3.证明定理:*如果我的typechecker将检查具有类型则存在在类型系统的导出表示具有类型。TeATeA
Andrej Bauer

我建议将2.和3.结合使用。另外,看看CompCert
安德烈·鲍尔

1
好答案。我要补充的一件事是类型系统的文献通常侧重于“健全性”定理,但是人们可能会关心的正确性的另一方面是“完整性”(这似乎在OP的“我希望我的类型检查器能够能够识别一段代码中在运行时可能发生的任何错误”)。特别是,除了您提到的定理之外,还可能希望建立:1.如果类型系统的派生表明具有类型,则类型检查器验证具有类型和/或2如果是...TeAeAe
Noam Zeilberger

...没有类型,则它在运行时不会表现出的预期行为(或更简单地说,如果是不可键入的,则在运行时会出错)。这些完整性方面有时被忽略的原因之一是,随着类型系统变得更具表现力,它们可能会遇到不确定性问题(并且在1和2之间进行权衡:随着类型系统变得更具表现力,可以捕获错误,变得更加困难)自动类型检查)。尽管如此,有时还是有可能证明这种健全性和完整性定理,...A eAAe
Noam Zeilberger

5

“证明我的类型检查器可以工作”可能意味着几件不同的事情。我想这是您的问题要问的一部分;)

这个问题的一半证明您的类型足以证明语言的任何特性。Andrej的答案非常适合imo。问题的另一半是-假设语言及其类型系统已经固定-您如何证明您的特定类型检查器确实正确地实现了类型系统?我可以看到这里有两个主要观点。

一种是:我们怎么能相信某个特定的实现符合其规范?根据所需的保证程度,您可能对大型测试套件感到满意,或者可能需要某种形式的正式验证,或者更可能是两者的混合。这种观点的好处在于,它确实突出了为正在提出的主张设置界限的重要性:“正确”的确切含义是什么?检查代码的哪一部分,而假定正确的TCB是哪一部分?不利的一面是,对这一问题进行过认真的思考会导致一个哲学上的兔子洞倒下 -好吧,如果您不喜欢那些兔子洞,那就是“缺点”。

第二个观点是对正确性的更数学的认识。在数学中处理语言时,我们经常为“理论”建立“模型”(反之亦然),然后尝试证明:(a)我们在模型中可以做的理论中可以做的一切,以及(b)我们在模型中可以做的一切,在理论上可以做的。(这些是健全性完整性定理。哪一个取决于您是从语法理论还是从语义模型“开始”。)使用这种思维方式,我们可以将类型检查实现视为所讨论类型理论的特定模型。因此,您想证明实现可以做什么和理论上应该做到的之间是双向的。这种观点的好处在于,它的重点实际上在于您是否涵盖了所有极端情况,在不遗漏任何应接受为类型安全的程序的意义上实现是否完整以及实现是否合理。不要让任何程序接受它的错误类型的感觉。缺点是您的对应关系证明很可能与实现本身完全分离,


我不确定我是否可以同意“这种观点的观点是,它实际上着重于您是否涵盖了所有极端情况”,尤其是在模型只是健全而又不完整的情况下。我会提出不同的观点:遍历模型是一种偶然证明技术,出于各种原因(例如,因为模型更简单),您可以使用它。从理论上讲,没有什么比通过模型更为庄重了-最终您想了解实际的可执行文件及其行为。
Martin Berger

我认为“模型”和“理论”是广义的意思,而雷恩只是强调尝试通过“健全性+完整性定理”建立双向对应关系的重要性。(我也认为这很重要,并且对Andrej的文章进行了评论。)的确,在某些情况下,我们只能证明稳性定理(或完整性定理,取决于您的观点),但具有两个方向记住这是有用的方法论约束。
Noam Zeilberger

1
@NoamZeilberger“问题是,”马丁说,“是否可以使单词代表那么多不同的事物。”
Martin Berger

当我学习了类型系统和编程语言语义时,我发现模型仅仅是关于操作语义的证明技术,而不是最终以自身为最终目的的自由解放。
Martin Berger

1
通过稳健性和完整性联系不同的模型是传递见解的重要科学方法。
Martin Berger
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.