我在大学时被告知formal systems,但我很失望,他们似乎没有在真正的单词中使用它们。
我喜欢能够知道某些代码(对象,函数,等等)的工作原理,不是通过测试,而是通过证明。
我确信我们都熟悉物理工程和软件工程之间不存在的相似之处(钢铁行为可预测,软件可以做任何事情 - 谁知道!),我很想知道是否有任何可以在真实单词中使用的语言(要求提供过多的Web框架?)
我听说过像scala这样的函数式语言的可测试性。
作为软件工程师我们有什么选择?
答案 0 :(得分:34)
是的,有些语言专为编写可证明正确的软件而设计。有些甚至用于工业。 Spark Ada可能是最突出的例子。我和Praxis Critical Systems Limited的一些人谈过,他们用它来运行Boings上的代码(用于引擎监控),看起来相当不错。 (这是一个很棒的summary / description of the language。)这种语言和随附的证明系统使用下面描述的第二种技术。它甚至不支持动态内存分配!
我的印象和经验是,有两种编写正确软件的技巧:
技巧1:用您熟悉的语言(例如C,C ++或Java)编写软件。正确地说明这种语言,并证明你的程序是正确的。
如果你的目标是100%正确(这通常是汽车/航空航天业的要求),你将花费很少的时间编程,并且有更多的时间证明。
技巧2:用稍微笨拙的语言(例如Ada的某个子集或OCaml的调整版本)编写软件,并在此过程中编写正确性证明。编程和证明在这里齐头并进。 Coq中的编程甚至完全等同于它们! (见Curry-Howard correspondence)
在这些情况下,您总会得到一个正确的程序。 (一个bug将保证在规范中扎根。)你可能会花更多的时间在编程上,但另一方面,你在整个过程中证明它是正确的。
请注意,这两种方法都取决于您手头有正式规范的事实(如何判断正确/不正确的行为),以及正式定义的语言语义(您还能怎样告诉我们什么?你的程序的实际行为是。)。
以下是一些正式方法的例子。如果它是“现实世界”,取决于你问的是谁: - )
我只知道一种“可证明正确的”网络应用语言:UR。 “通过编译器”的Ur程序保证不会:
答案 1 :(得分:22)
为了回答这个问题,你真的需要用“可证明的”来定义你的意思。正如Ricky指出的那样,任何带有类型系统的语言都是一种内置证明系统的语言,每次编译程序时都会运行。这些证明系统几乎总是令人遗憾地无能为力 - 回答诸如String
vs Int
之类的问题并避免诸如“列表是否排序?”之类的问题。 - 但它们是证据系统,不过不可能。
不幸的是,您的证明目标越复杂,使用可以检查您的证据的系统就越难。当您考虑图灵机上不可判定的类问题的绝对大小时,这会很快升级为不可判定性。当然,理论上你可以做一些基本的事情,例如证明你的排序算法的正确性,但除此之外的任何事情都将在非常薄的冰上进行。
即使要证明像排序算法的正确性这样的简单需要相对复杂的证明系统。 (注意:既然我们已经确定类型系统是一种内置于语言中的证明系统,我将用类型理论来讨论事物,而不是更加努力地挥动我的手)我很确定列表排序的完整正确性证明需要某种形式的依赖类型,否则您无法在类型级别引用相对值。这立即开始进入类型理论领域,这已被证明是不可判定的。因此,虽然您可能能够在列表排序算法上证明正确性,但唯一的方法是使用一个系统,该系统还允许您表达无法验证的证据。就个人而言,我觉得这非常令人不安。
我之前提到过易用性方面。您的类型系统越复杂,使用起来越不愉快。这不是一个严格而快速的规则,但我认为它在大多数情况下都适用。和任何正式系统一样,您经常会发现表达证据比首先创建实现更有效(并且更容易出错)。
尽管如此,值得注意的是Scala的类型系统(如Haskell)是Turing Complete,这意味着您可以理论上使用它来证明关于代码的任何可判定属性,前提是您已经以适合此类证明的方式编写了代码。 Haskell几乎肯定是比Java更好的语言(因为Haskell中的类型级编程类似于Prolog,而Scala中的类型级编程更类似于SML)。我并不建议您以这种方式使用Scala或Haskell的类型系统(算法正确性的形式证明),但理论上可以选择该选项。
总而言之,我认为你在“现实世界”中没有看到正式系统的原因源于这样一个事实,即形式证明系统已经屈服于实用主义的无情暴政。正如我所提到的,在制作正确性证明方面需要付出很多努力,以至于它几乎不值得。很久以前,业界决定创建临时测试比通过任何分析形式推理过程更容易。
答案 2 :(得分:10)
键入的语言证明没有某些类别的错误。类型系统越先进,它们就越能证明没有。
为了证明整个程序是有效的,是的,你走出了普通语言的界限,数学和编程相遇,握手,然后继续使用希腊符号谈论程序员如何处理希腊语符号。无论如何,这都是关于它的Σ。
答案 3 :(得分:10)
你问了我们很多年来问过的问题。我不知道我有一个好的答案,但这里有一些部分:
有一些易于理解的语言,有可能在今天被证明使用;通过ACL2的Lisp是一个,当然,Scheme也有一个易于理解的正式定义。
许多系统都试图使用纯函数式语言,或几乎纯粹的函数式语言,如Haskell。在Haskell中有一些正式的方法。
回溯20多年,使用正式语言的手工证明是一件短命的事情,然后将其严格翻译成编译语言。一些例子是IBM的软件清洁室,ACL,Gypsy和计算逻辑的Rose,John McHugh和我关于C的可靠编译的工作,以及我自己关于C系统编程的手工证明的工作。这些都得到了一些关注,但没有一个在实践中付诸实践。
我认为,一个有趣的问题是,将正式方法付诸实践的充分条件是什么?我很乐意听到一些建议。
答案 4 :(得分:4)
您可以调查纯函数式语言,例如Haskell,当您的一个要求是可证明性时使用。
如果您对函数式编程语言和纯函数式编程语言感兴趣,那么This是一个有趣的读物。
答案 5 :(得分:4)
现实世界对这种可证明语言的使用将非常难以编写和理解后木材。 商业世界需要快速的工作软件。
“可证明的”语言只是为了编写/阅读大型项目的代码库而无法扩展,并且似乎只能在小而孤立的用例中工作。
答案 6 :(得分:4)
查看Omega。
此introduction包含一个相对无痛的AVL树实现,其中包含正确性证明。
答案 7 :(得分:4)
我参与了两种可证明的语言。第一个是Perfect Developer支持的语言,这是一个用于指定sotfware,改进它并生成代码的系统。它已被用于一些大型系统,包括PD本身,并在许多大学教授。我参与的第二种可证明语言是MISRA-C的可证明子集,请参阅C/C++ Verification Blog了解更多信息。
答案 8 :(得分:3)
编辑===== 删除了关于ML“可证明”的错误观点。
答案 9 :(得分:3)
我(有争议的)定义"现实世界"在可证明正确的代码的上下文中:
以上是相对更普遍的要求。其他的,例如模拟命令式代码的能力,或证明高阶函数正确的能力,对于某些任务可能是重要的或必不可少的,但不是全部。
鉴于这些观点,this blog post of mine中列出的许多工具可能都很有用 - 尽管它们几乎都是新的和实验性的,或者对绝大多数行业程序员来说都不熟悉。虽然有一些非常成熟的工具。
答案 10 :(得分:2)
作为一个很好的现实生活示例,有一个项目旨在提供一个用Agda编写的经过验证的HTTP REST库,名为Lemmachine:https://github.com/larrytheliquid/Lemmachine