YNot项目

YNot项目

Ynot项目的目标是使依赖类型的编程成为现代编程语言的实用程序。特别是,我们正在扩展Coq证明助手,使之能够通过Hoare类型理论(HTT)的浅嵌入来编写高阶、命令式和并发程序(Haskell风格)。HTT在纯计算和有效计算之间提供了一个干净的分离,使得形式化地指定和推理效果成为可能,并且是完全复合的。

这实际上是评论在这里,作者是格雷格·莫里塞特本人。从概念上讲,这似乎和亚当·克利帕拉的有关从Lambda演算到汇编语言的一个经过认证的类型保持编译器. 请特别参见第23-24页的幻灯片本演示文稿(PDF格式)。更一般地说,计算和反射似乎正被视为Coq等强大工具实际使用的重要特性;另请参阅顾客满意度评价策略及其随行文件Coq系统的小尺度反射扩展(PDF格式)。

有趣的是,观察到这项工作似乎依赖于即将发布的coq8.2中的“Program”关键字,后面的工作被称为“Russell”,如中所述这条线. 与此同时,Russell的主页是在这里. 同样,重点是简化Coq中依赖类型的编程。

更新:一些初步代码可以从项目页面获得。

评论查看选项

点击“保存你的评论”来保存你的设置。

实用步骤

那么,这里的路线图是什么?当然,我们不能指望真正的程序员用Coq语法编写代码。我们是否定义了一个好的主流友好的语言语法,将其翻译成Coq进行排版,然后将其翻译成某种运行时形式,如果程序成功地进行了类型检查,那么这种翻译是正确的吗?

这种对有效果的东西的特殊语法很糟糕,而且与主流的实践和直觉背道而驰,例如“IO Int”和“Int->IO Int”对“Int”和“Int->Int”。我们应该隐式地将所有计算封装在monad中,例如,对于上下文相关的monad M,让Int->Int compile to Int->M(Int),并将“let x=a in bx”编译为“a>==\x->bx”。然后,语法对于各种效果都是规则的,包括“无”。您可以使用“mdo”文章中描述的递归monad来分离语言的全部部分(不带递归的标识monad)、部分部分(递归标识monad)以及各种有效部分——异常、状态线程、IO。

此外,强迫程序员生成证据并将其传递给除普通参数外的函数,例如调用函数并将其传递给整数以及整数在0和n之间的证明,这是不合理的。最好有一个更具表现力的类型系统和适当的子类型,例如自然数的类型小于n作为整数的一个子类型。

回复:诱骗程序员使用它

在我看来,如果你从“你正在写证明”的角度来看待功能,人们会因为“证明”的含义而回避它。另一方面,如果你只说“哦,嘿,我们现在有了更细粒度的类型”,人们可能会更感兴趣。即使最后基本上是一样的?比如说,说编译器的类型检查器可以“免费”地为您证明一些事情,但说您必须编写证明是可怕的,即使人们习惯于编写类型。

首先需要学习如何使用现有的类型系统

我认为即使是非常优秀的程序员也可以接受培训,学习如何在C++等语言中最好地使用类型系统。

上周,我在一个大型的C++应用程序中遇到了一个bug,这个bug可以归结为不规范的url。我怀疑(但公平地说,不确定)URL是作为字符串传递的,而不是使用某种URL类型/类来表示的。如果字符串尽早被转换为URL类型,那么简单的面向对象就足以防止错误的发生。

在我看来,依赖类型是一个直觉上正确的想法,但是我想知道在实践中有多少错误可以通过巧妙(或不那么聪明)地使用标准C++类型系统来避免。人们能给我举一些真实世界的bug的例子吗?这些bug可以通过一些类似于YNot的东西而不是C++类和模板来防止?

你的错误类型

你所描述的那种错误是很常见的。我认为这比不使用类型系统要重要得多(当然,也是如此)。这是对软件设计中抽象的价值缺乏理解(在本例中是ADTs)。

但是。。。

首先需要学习如何使用现有的类型系统

但工业实践通常落后于研究前沿10至20年。随着依赖时间的类型被广泛使用,一般的编码者可能只会胜任一阶多态类型。

人们能给我举一些真实世界的bug的例子吗?这些bug可以通过一些类似于YNot的东西而不是C++类和模板来防止?

首先,让我说,谈论C++模板是非常棘手的。每当有人说“你不能这样做”的时候,就会有人用一个非常聪明的棍子把一个巨大的小球砍下来,这个小球可以“做这个。”——)

不管怎样,你谈到了URL编码程序。当然,拥有一个带有仔细保护的工厂和转换例程的URL类型对于消除URL相关的bug有很大的帮助。我不能反驳。但是,当您构建这些转换时,您没有证据表明您的url实际上符合您想要的属性。取而代之的是你必须依靠测试或手工证明。

你用了“真实世界”这个词,这是个很有意思的短语。根据我的经验,每个人都生活在自己的小“现实世界”中,从实用性/经济性/安全性的角度来看,在某些领域中,C++提供的各种证明实际上已经足够了。在其他领域,可能需要更好的证明。URL类型是前者还是后者?这不是一个简单回答的问题。

挑战。。。

…在我看来,是把今天可以做的事情(C++模板元编程、“ML或Haskell中的“类型化”编程)加上一点今天不能做的,使之不仅不难做,而且实际上很容易,而且在十年左右的时间里,就像今天的面向对象一样显而易见(即“你会怎么做?”)

另一方面,如果你

另一方面,如果你只说“哦,嘿,我们现在有了更细粒度的类型”,人们可能会更感兴趣。即使最后基本上是一样的?

我同意。在代码中传递证明的想法看起来很像是一个有充分基础的契约式设计系统。当你在写一个函数的时候,你必须展示一个函数,当你需要一个函数的时候,你必须展示它。对我来说,这听起来不那么“威胁”,就像它是在编译时验证的契约式设计。

我看不出来

试图向程序员推销“哦,我们有更细粒度的类型”可能会让人们事先更感兴趣,但程序员很快就会试图将值传递给“显然”是参数类型的子类型的函数,如果编译器向他抱怨,我想兴趣会很快减弱。

显然

我认为“明显性”的一个重要衡量标准是是否有一个决策过程来证明子类型实际上是一个子类型。我认为你是对的,必须手动解除太多的举证责任是行不通的。但手动证明一些更有趣的方法可能并不坏。

还是看不见

我在引号中加上“显然”的原因是,我认为有很多东西程序员会觉得很明显,但用你的[*]这样的定义是不明显的。其中许多甚至可能是真的。

比较合并排序的版本为什么依赖类型很重要. 我可以断言,mergeSort使用轻量级类型注释简单地保留了长度——显然,要用警句来证明这些断言,要做的工作要多得多。还要注意的是,论文指出,修改定义以便于证明更容易——我不知道如果你只是写下算法并试图证明这一属性,你的情况会有多糟糕。

或者本演示文稿讨论(p25)Coq中的编译器实现:

4000行编译器:
7000行引理和定理包括C和PPC代码的解释器/模型—许多在其他上下文中是可重用的
17000行的验证脚本虽然有正确的策略,但至少可以削减一半。记住,这是一个很深的属性。

考虑到证明行的数量是要证明的断言行数的两倍多,我们要么有很多事情需要人工干预,要么确实需要证明的事情很困难。编辑:这里2:1非常慷慨,因为程序员可能只关心其中几百条定理行,其他的都是支持引理的。

不过,主要的论点似乎是,即使有少数难证明的东西,强迫程序员去证明它们比仅仅告诉他它们还没有被证明有什么好处呢?

[*]我认为量词需要注意——对于任何可证明的子类型关系,都有一个决策过程来证明它。

没有什么能阻止你

没有什么能阻止你在你的类型中缺乏特色!我想保持“良好的类型足以运行”与“实际上按照规范所说的做”是有一定价值的,即“这段代码可以是良好类型的”与“这段代码具有所需的类型”。

我知道什么都没有

我意识到没有什么能阻止我对我的类型进行分类——我只是不想让即将到来的与类型检查器的死对决的恐惧驱使我对它们进行分类。我同意你的第二句话,我认为应该注意确保“好的打印足够运行”只是非常轻的键入(编辑阅读:可判定)

澄清

我不得不想象一下,我并不清楚:如果某件事有一个决策程序,那么要么Coq的用户必须使用它,要么Coq本身必须自动地应用它,使之具有说服力。也就是说,我只是用了一个稍微开玩笑的公式来观察到,认证软件的过程有很多,你想用Coq认证。

当然,引用的是你的陈述公司证书项目。这与使用依赖类型的“just”编程不同!这涉及到证明类C语言的所有源代码/目标代码对的语义等价性,这就是Greg Morrisett正确地将其称为表示中的“深层属性”的原因。Leroy使用了共归纳的大步操作语义,并取得了这个出色的结果,但是我有兴趣与Adam Chlipala在依赖类型的抽象语法和指称语义方面的工作进行比较和对比;请看他的幻灯片在这里,特别是幻灯片15,其中包含250行经过认证的CPS转换,以及幻灯片20,它提供了一些与您引用的类似的统计信息。然而,值得指出的是,CompCert处理的是一种非常类似C语言的、现实的语言,而到目前为止,Chlipala的工作仅限于一种相对简单的lambda语言。

当然,在这两种情况下,人们希望得到的是一个高度自动化的可重用组件库的集合,通过这些库,编译器开发人员可以使用Coq实现新的语言。从这个角度来看,Chlipala努力提供通用工具,并依靠Coq自己的metalogic使大多数传统类型的证明(例如,操作语义学中必需的进步和保存)变得不必要,这一点似乎很受欢迎,像U Penn这样的工具也是如此元理论库和微软的S反射战术。

但所有这些都与认证用Coq开发的编译器有关,这与使依赖类型编程更容易被更多程序员接受并不一定是一回事。我真的不希望在Coq中发生,但也许我提到的工具可以帮助人们设计和实现一种从Coq中提取的语言,它将成功地实现这个目标。

很多事情可以做

一个好的IDE和策略可以做很多事情,我想如果一个小家伙也能轻松地得到一些更复杂的情况,那么很多程序员会愿意让这个小家伙通过一种轻量级的方式说“替我填充它”。

听起来对我很好

就我而言,我更喜欢将单子更多地整合到语言中的想法。使用与一元计算相同的语法来表达纯函数似乎很重要,因为它使向纯函数添加一个简单的效果要容易得多。但是,我不认为你想对类型系统隐藏它。改进一元类型的语法,是的,但是程序员需要能够区分f::Int->Int和f::Int->IO Int。

我也同意您关于验证传递和子类型化的评论,尽管我对要求程序员证明这些属性持怀疑态度。我认为圣人这将导致一个很好的实践,通过不烦扰用户的相应值和一堆证明义务严格指定类型。

(另外,我不认为Coq在这种情况下如何适合作为一个打字机。你会自动插入战术吗?向程序员公开策略?)

好问题!

我有一个非常相似的反应:用Coq编程是一回事;使用Coq开发认证编译器是另一回事。

还是真的?我不得不承认我对程序设计语言语义支持的定理证明. 这是一个非常有趣的思考和提取练习,也就是说,你可以在小范围内使用Coq中的语言,然后提取一个解释器在Coq之外使用。原则上,没有理由解释程序不能成为编译器。所以在我看来,如果Ynot足够模块化,您可以根据需要使用Coq/Ynot进行编程,并将最终结果代码提取到Scheme、OCaml或Haskell;或者您可以只提取语义和代码gen啊,拉CompCert或Adam Chlipala的认证编译器,在其上安装一个解析器,并有一种“不同”的语言。这显然是一个过于简单化的魔鬼在细节上,所有这些,但我不认为这是一个离谱的目标。

至少,这并不比在一个proof assistant中为一个现实的、现代的编程语言开发一个经过认证的编译器没有什么比这更离谱的了。:-)

比你想象的要好

有些事情比你想象的要好。特别是拉塞尔扩展到
因为,这些证明实际上并不是“串联”的,而是作为
你可以独立于代码来构造。(你可以选择建立明确的证据
另外,你可以编写代码并注册战术
试图自动解除验证条件。最后,马修
Sozeau正在添加一些非常好的附加特性,包括对类型的支持-
类,这将使代码更易于读写。

我同意一些更好的外部语法是不错的,但是在这里您必须小心:
我们需要在很大程度上严格区分“纯”和“不纯”,以确保
当我们构造证明时,它们是有意义的*并且*它们可以在键入后被删除-
检查。(相比之下,Sage等语言必须依赖其他技术来
尽量确保规范中可能发生的“影响”是良性的。
类似地,在哈斯凯尔(Haskell)中尝试嵌入这种东西,比如卡宴,
因为可以使用异常或分歧,所以会陷入根本的不健全
建立“错误”的证明。)

说到这里,我认为这里的句法结构并不理想
还有很大的改进空间。但在这一点上,我们要确保
我们可以编写真正的代码来使用效果,并证明深层属性
关于他们。

我们确实有一些非常简洁的代码——我最喜欢的是AviShinnar的
依赖哈希表(其中与键关联的值的类型是依赖的
钥匙上)。迭代器有更高阶的函数
通过有效的计算,但你仍然可以推理
可能的影响。接口只告诉您所有的key*value对
将呈现给你的功能,但不是什么顺序。这给了你
改变抽象实现的自由(例如,改变到任何东西
它实现了一个有限映射),但也给了你足够的推理能力
如果你想在哈希表上映射一个函数
将每个key*value对插入另一个(最初为空)哈希表,然后
最后可以得出结论,它们都实现了相同的有限映射。

其他例子包括记忆(依赖)函数
确保类型记忆化
解析组合词,类型告诉你解析器的语法
会接受的。

所以无论如何,是的,我们还有很长的路要走,才能真正准备好
世界(真的不真实),但是Coq(真的是罗素)提供了一个很好的环境
快速形成创意原型。

Scala中的依赖类型

我最喜欢的是Avi Shinnar实现的依赖哈希表

迈尔斯萨宾已经意识到这一点了不成形的为了斯卡拉。

我玩了这个把戏

我在Scala工作的时候就经常玩这个把戏。它在C中也能很好地使用普通的老泛型(可能也是Java),尽管不是很好。

这似乎是个不成形的把戏

看起来这个不成形的技巧需要更高的种类,所以我不清楚如何在C的泛型中使用这种方法。

完全不成形的把戏

完整的无形状技巧需要更高的种类,但是如果你只是想要一个“智能”字典,你可以很容易地根据它的键类型改变它的元素类型;例如。,

T Get[T](此词典[IKey,object],IKey[T]键){。。。}

亚型

另外,强迫程序员生成证据并将其传递给除普通参数外的函数,例如调用函数并将其传递给整数以及整数在0和n之间的证明,这是不合理的。最好是有一个更具表现力的类型系统和适当的子类型,例如自然数的类型小于n作为整数的一个子类型。

这正是罗素在Coq中所允许的。你编写程序时就好像没有涉及到任何证明,它会完成所有的证明传递。

标注

我已经更新了引导故事,以反映新的项目URL,并且有可用的初步代码。

SSReflect的URL

请注意,Coq的SSReflect策略的URL已过时。SSReflect战术的最新版本现在已经找到了在这里.