Haskell函数可以certificate/模型检查/validation的正确性属性?

继续从下面的想法: 有没有任何可证实的现实世界的语言?

我不了解你,但是我厌倦了写我不能保证的代码。

在问上面的问题并得到一个惊人的回应(谢谢所有!)我已经决定缩小我的search一个可certificate的,实用的方法, 哈斯克尔 。 我select了Haskell是因为它确实有用(有很多为它编写的Web 框架 ,这似乎是一个很好的基准) 我认为它在function上是足够严格的,它可能是可certificate的,或者至less允许testing不variables。

这是我想要的 (而且一直无法find)

我想要一个框架,可以看看一个Haskell函数,添加,写在psudocode:

add(a, b): return a + b 

– 并检查某些invarients是否保留每个执行状态。 我更喜欢一些正式的证据,但我会解决像模型检查。
在这个例子中,不variables是给定值ab ,返回值总是和a + b

这是一个简单的例子,但我不认为这样的框架是不可能存在的。 一个函数的复杂性肯定会有一个上限,可以被testing(一个函数的10个stringinput肯定需要很长时间!),但是这会鼓励更仔细的函数devise,并且与使用其他forms方法。 想象一下,使用Z或B,当你定义variables/设置时,你要确保你给variables尽可能小的范围。 如果你的INT永远不会超过100,那么确保你初始化它! 像这样的技术和适当的问题分解应该 – 我认为 – 允许对像Haskell这样的纯函数语言进行满意的检查。

我还没有很正式的方法或Haskell经验。 让我知道,如果我的想法是一个健全的,或者你认为哈斯克尔不适合? 如果您build议使用不同的语言,请确保它通过“has-a-web-framework”testing,并阅读原始问题 🙂

那么,有几件事情要开始,因为你正在采取哈斯克尔路线:

  • 你是否熟悉咖喱霍华德的信件 ? 有一些系统用于基于此的机器检查certificate,在许多方面,这些系统只是具有非常强大types系统的function性编程语言。

  • 您是否熟悉抽象math领域,为分析Haskell代码提供有用的概念? 各种各样的代数和一些类别理论的味道出现了很多。

  • 请记住,像所有图灵语言一样,Haskell总是有可能不终止。 一般来说,要certificate某些东西永远是真实的,要比certificate某件事是真实的还是取决于非限制性的价值要困难得多。

如果你认真去certificate ,而不仅仅是testing ,这些都是要记住的事情。 基本的规则是:使无效状态导致编译器错误。 首先防止无效数据被编码,然后让types检查器为您做一些冗长的工作。

如果你想更进一步,如果内存服务于我的certificate助手Coq有一个“提取到Haskell”的function,可以让你certificate关键函数的任意性质,然后把certificate变成Haskell代码。

为了在Haskell中直接做类似系统的东西, Oleg Kiselyov是大师 。 你可以在他的站点上find像高级多态types这样的整洁技巧的例子来编码数组边界检查的静态certificate 。

对于更轻量级的东西,你可以做一些事情,比如使用types级别的证书来标记数据被检查为正确。 你仍然是自己检查自己的正确性,但其他代码至less可以依靠知道一些数据实际上已经被检查。

您可以采取的另一个步骤是构build轻量级validation和花哨型系统技巧,这是因为Haskell可以很好地用作embedded特定领域语言的宿主语言 ; 首先构造一个严格受限的子语言(理想情况下,不是图灵完备的),然后使用该DSL中的程序来提供关键的核心function。 例如,你可以certificate一个双参数函数是关联的,以证​​明使用该函数并行减less项目集合的合理性(因为函数应用程序的sorting并不重要,只有参数的sorting)。


哦,最后一件事。 关于避免Haskell确实包含的缺陷的一些build议,这些缺陷可能会破坏本来可以安全使用的代码:这里你的死敌是一般recursionIO monad部分函数

  • 最后一个比较容易避免:不要写下来,也不要使用它们。 确保每一组模式匹配处理每一个可能的情况,并从不使用errorundefined 。 唯一棘手的部分是避免可能导致错误的标准库函数。 有些显然是不安全的, fromJust :: Maybe a -> a或者是head :: [a] -> a但其他的可能会更加微妙。 如果您发现自己编写的函数确实无法对某些input值进行任何操作,那么您将允许inputtypes对无效状态进行编码,并首先需要对其进行修复。

  • 第二个方法很容易避免在表面层次上通过散列东西,通过从IOexpression式中使用的各种纯函数。 更好的做法是尽可能将整个程序移出纯代码,以便除了实际的I / O之外的任何事情都可以独立评估。 这只有当你需要由外部input驱动的recursion时才会变得棘手,这会使我得到最终的结果:

  • 明智之语: 有根据的recursion有效的核心竞争 。 始终确保recursion函数要么从一个起点到一个已知的基本情况,要么正在生成一系列要素。 在纯代码中,最简单的方法是通过recursion折叠有限的数据结构(例如,而不是直接调用自己的函数,而将计数器增加到某个最大值,创build一个包含计数器值范围的列表并将其折叠)或recursion地生成一个懒惰的数据结构(例如逐渐逼近某个值的列表),同时小心地不要直接混合这两个数据结构(例如,不要只是“find符合某种条件的stream中的第一个元素”;它可能不会存在,取而代之的是从stream中取值到某个最大深度,然后search有限清单,适当地处理未find的案例)。

  • 结合最后两项,对于真正需要IO的部分,需要使用一般recursion,尝试将程序构build为增量组件,然后将所有不好的位压缩到一个“驱动程序”函数中。 例如,你可以用一个纯函数来编写一个GUI事件循环,比如mainLoop :: UIState -> Events -> UIState ,退出testing如quitMessage :: Events -> Bool ,一个函数getEvents :: IO Events ,和一个更新函数updateUI :: UIState -> IO () ,然后用runLoopIO :: (b -> a -> b) -> b -> IO a -> (b -> IO ()) -> IO () 。 这使复杂的部分保持纯真,让你用事件脚本运行整个程序,并检查所产生的UI状态,同时将难以处理的recursionI / O部分分离成单个抽象函数,这些函数易于理解并且通常是不可避免的通过参数化 。

可能最接近你要求的是Haskabelle ,一个与certificate助手Isabelle一起的工具,它可以将Haskell文件翻译成Isabelle理论,并让你certificate他们的东西。 据我所知,这个工具是在HOL-ML-Haskell项目中开发的, 他们的主页包含一些关于背后理论的信息。

我对这个项目不是很熟悉,对这个项目已经做了很多了解。 但是我知道Brian Huffman一直在玩弄这些东西,看看他的论文和会谈,他们应该包含相关的东西。

我不确定你所要求的究竟是什么让你快乐。 🙂

对通用语言进行模型检查几乎是不可能的,因为模型必须是特定领域的才能实用。 由于哥德尔的不完全性定理, 没有一种方法可以自动地find充分expression逻辑的certificate

这意味着你必须自己写certificate ,这就提出了这个努力是否值得花时间的问题。 当然,这种努力创造了非常有价值的东西,也就是保证你的程序是正确的。 问题不在于这是否是必须的,而在于花费的时间是否太大。 关于certificate的事情是,虽然你可能有一个“直觉”的理解,即你的程序是正确的 ,但把这种理解forms化为certificate往往是非常困难的 。 直觉的理解问题是它很容易发生意外错误(拼写错误和其他愚蠢的错误)。 这是编写正确程序的基本困境。

因此,关于程序正确性的研究就是要使certificate的forms化和自动检查正确性变得容易。 编程是“易于forms化”的一个组成部分; 以易于理解的风格编写程序是非常重要的。 目前我们有以下几个方面:

  • 像C,C ++,Fortran,Python这样的命令式语言:这里很难forms化任何东西。 unit testing和一般推理是获得至less一些保证的唯一方法。 静态types只能捕获微不足道的错误(比没有捕获它们好得多!)。

  • 像Haskell,ML这样的纯function语言:expression式types系统有助于捕捉不重要的错误和错误。 手工certificate正确性对于200线左右的片段是实用的,我想说。 (例如,我为我的操作包做了一个certificate。) Quickchecktesting是forms化certificate的廉价替代。

  • 依赖型语言和certificate助手,如Agda,Epigram,Coq:certificate整个程序的正确性是可能的,这要归功于certificateforms化和发现的自动化帮助。 但是,这个负担还是很大的。

在我看来,现在编写正确程序的甜蜜点是纯粹的函数式编程 。 如果生命取决于你的程序的正确性,你最好更高一级,并使用certificate助手。

听起来像你想ESC / Haskell: http : //research.microsoft.com/en-us/um/people/simonpj/papers/verify/index.htm

呵呵,Agda现在有一个networking框架(至less有概念certificate): http : //www.reddit.com/r/haskell/comments/d8dck/lemmachine_a_web_framework_in_agda/

你有看看快速检查? 它可能提供一些你需要的东西。

http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck

你看似简单的例子,加(a,b),实际上很难validation – 浮点,溢出,下溢,中断,是编译器validation,是硬件validation等。

习惯是Haskell的一种简化的方言,可以certificate程序的属性。

休谟是一个有5个级别的语言,每个语言都更有限,因此更容易validation:

充分的休谟
  完全recursion
 PR  - 休谟
  原始recursion函数
模板 - 休谟
  预定义的高阶函数
  归纳数据结构
  归纳非recursion一阶函数
 FSM  - 休谟
  非recursion数据结构
 HW-休谟
  没有function
  非recursion数据结构

当然,今天用于certificate程序特性的最stream行的方法是unit testing,它提供了强大的定理,但这些定理过于具体。 “types被认为是有害的”,皮尔斯,幻灯片66

看看芝诺 。 引用wiki页面:

Zeno是Haskell程序属性的自动化certificate系统; 由William Sonnex,Sophia Drossopoulou和Susan Eisenbach在伦敦帝国学院开发。 它旨在解决任何input值的两个Haskell术语之间的一般性问题。

目前可用的许多程序validation工具都是模型检查types; 能够非常快速地遍历非常大但有限的search空间。 这些非常适合于描述较大的问题,但不适用于recursion数据types。 另一方面,Zeno被devise为在无限的search空间中归纳地certificate属性,但是只有那些规格小而简单的属性。

当然可以正式certificateHaskell程序的一些属性。 我必须在我的FP考试中这样做:给出两个expression式,certificate它们表示相同的function。 由于Haskell是图灵完备的,所以一般不可能做到这一点,所以任何机械certificate者要么必须是certificate助手(半自动的用户指导)或者模型检查者。

这方面的尝试,例如见P逻辑:Haskell程序的属性validation,或者使用Mizarcertificatefunction程序的正确性 。 两者都是描述方法而不是实现的学术论文。

MSR剑桥最近的一些努力: http : //research.microsoft.com/en-us/um/people/simonpj/papers/verify/hcc-popl.pdf

AProVE工具(至less)能够certificateHaskell程序的终止,这是certificate正确性的一部分。 更多的信息可以在这篇文章中find( 更短的版本 )。

除此之外,你可能对依赖types感兴趣。 在这里,types系统被扩展并用于使错误的程序不可能。