为什么没有设计完全编译检查的语言?

时间:2013-11-05 05:18:34

标签: programming-languages

原谅设计非常糟糕的伪代码,但我希望它能解决这个问题:

float sqrt takes float n : [0,inf)
    // fancy algorithm
    return result

void main
    x = sqrt -1             // Compilation error
    y = sqrt float.max      // This works
    z = (y + 1) * (y + 1)   // Compilation error (this would result in overflow)

在编译期间,编译器会分析sqrt函数并将其表征为

sqrt : [0,float.max] -> [0, sqrt float.max[

通过对+, -, *, /运算符执行相同操作来实现此目的。


main函数中,第一个语句无法编译,因为sqrt不接受负输入。第三个语句不编译,因为*运算符只接受会导致[float.min, float.max]输出的输入。

2 个答案:

答案 0 :(得分:6)

您正在寻找的是COQ,Agda和Idris等语言,其中类型系统允许通过值对类型进行参数化。 (依赖类型)

这并不像您想象的那么容易,并且通常需要完整的证据(在通话方面)才能满足条件。在你的情况下,你必须证明sqrt的参数不能是负数。

的情况很简单
sqrt(5)

但在以下情况下并不那么容易:

sqrt(some_long_computation_on_floats(f))

您需要在此证明some_long_computation_on_floats只返回正数。可能会或可能不会。

答案 1 :(得分:3)

您可能希望阅读design by contract。特别是,有许多语言和语言扩展支持在代码中设置复杂的合同,其中一些可以在编译时检查。一个简单的例子是JML - 事实上,this paper about JML的第一页有以下sqrt合同:

//@ requires x >= 0.0;
//@ ensures JMLDouble.approximatelyEqualTo(x, \result * \result, eps);
public static double sqrt(double x) {
    /*...*/
}

确实有一些工具可以在不运行代码的情况下检查合同违规情况,例如ESC/Java

现在,按合同设计实际上非常受欢迎,因为静态类型语言中的类型声明实际上是一种合同形式。然而,更复杂的合同远没那么受欢迎,我会说因为:

  1. 编写复杂的合同可以快速 详细
  2. 错误可能会蔓延到复杂的合同中,这会让你回到原点1 - 谁会检查合同?
  3. 在编译时检查复杂的合同通常是:
    1. 计算成本高昂
    2. 产生大量误报(或者更糟糕的是,有假阴性)
  4. 还有其他可接受的检查代码的技术,最常见的是使用自动化测试。