Programming languages 是否有一种语言可以让类型考虑字段的内容?

Programming languages 是否有一种语言可以让类型考虑字段的内容?,programming-languages,types,type-systems,Programming Languages,Types,Type Systems,我有一个疯狂的想法,想知道是否存在这样的事情: 通常,在强类型语言中,类型主要与内存布局或抽象“类”的成员身份有关。所以class Foo{int a;}和class Bar{int a;int b;}是不同的,但是class Baz{int a;int b;}也是不同的(虽然它有相同的布局,但它是不同的类型)。到目前为止,一切顺利 我想知道是否有一种语言允许人们指定更细粒度的约束来表示类型的构成。例如,我想要: class Person { //... int height;

我有一个疯狂的想法,想知道是否存在这样的事情:

通常,在强类型语言中,类型主要与内存布局或抽象“类”的成员身份有关。所以
class Foo{int a;}
class Bar{int a;int b;}
是不同的,但是
class Baz{int a;int b;}
也是不同的(虽然它有相同的布局,但它是不同的类型)。到目前为止,一切顺利

我想知道是否有一种语言允许人们指定更细粒度的约束来表示类型的构成。例如,我想要:

class Person {
    //...
    int height;
}

class RollercoasterSafe: Person (where .height>140) {}

void ride(RollercoasterSafe p) { //... }

编译器将确保在
ride
中不可能有
p.height<140
。这只是一个愚蠢的例子,但我相信在某些用例中,这确实会有所帮助。有这样的东西吗?

我不知道有哪种语言支持这种东西,但我觉得没有必要

我非常确信,只要在属性的setter中应用验证,就可以提供所有必要的限制


在您的
RollercoasterSafe
类示例中,当height属性的值设置为小于140的值时,可能会引发异常。这是运行时检查,但多态性会使编译时检查变得不可能。

您的想法听起来有点像C++0x的概念,但并不完全相同。但是,概念已从C++0x标准中删除。

这取决于谓词是静态检查还是动态检查。在这两种情况下,答案都是肯定的,但最终的系统看起来不同

在静态方面:PL研究人员提出了细化类型的概念,它包括一个基类型和一个谓词:。我相信精化类型的思想是在编译时检查谓词,这意味着您必须将谓词的语言限制为可处理的语言

还可以使用依赖类型表示约束,依赖类型是由运行时值参数化的类型(与多态类型相反,多态类型由其他类型参数化)

对于Haskell等功能强大的类型系统,您还可以使用其他技巧,但IIUC必须将
高度
int
更改为类型检查器可以推理的结构

在动态端:SQL有一个称为域的东西,如
createdomain
:(参见页面底部的一个简单示例),它同样由一个基本类型和一个约束组成。每当创建域的值时,就会动态检查该域的约束。通常,可以通过创建新的抽象数据类型并在创建抽象类型的新值时执行检查来解决此问题。如果您的语言允许您定义从新类型到新类型的自动强制,那么您可以使用它们来实现类似SQL的域;如果不是这样,您就只能使用普通的旧抽象数据类型


还有一些契约,它们本身不被认为是类型,但可以以一些相同的方式使用,例如约束函数/方法的参数和结果。简单契约包括谓词(例如,“接受高度大于140的Person对象”),但契约也可以是高阶的(例如,“接受其MakeSalltalk()方法从不返回null的Person对象”)。高阶合约无法立即检查,因此它们通常涉及创建某种代理。合同检查不会创建新类型的值或标记现有值,因此每次执行合同时都会重复动态检查。因此,程序员通常沿模块边界签订合同,以尽量减少冗余检查。

具有此类功能的语言示例如下。从项目站点上提供的教程文档中:

考虑图1中的方法ISqrt,它计算 给定的整数x。只有当x为非负时,才能实现该方法,因此

int ISqrt(int x) 
  requires 0 <= x; 
  ensures result*result <= x && x < (result+1)*(result+1); 
{ 
  int r = 0; 
  while ((r+1)*(r+1) <= x) 
    invariant r*r <= x; 
  { 
    r++; 
  } 
  return r; 
} 

可能有一种方法可以将
requires
子句汇总到您建议的类型声明中,例如
RollercoasterSafe

我认为Haskell或Eiffel可能会这样做。编译器应该如何确保约束?它在编译时不知道Person实例的任何值?@Chris Dennett:据我所知,Eiffel支持前置和后置条件,但它们“只”像资产。这可以帮上大忙,但这只是事情的一半。当你输入错误的值时,你的程序仍然会中止(我猜!我承认我自己没有试过埃菲尔)。@user:我还没想出来。例如,编译器可以防止您使用空值。这只是它的延伸。变量开始时是不安全的(特定用途),并且可以通过某些操作标记为安全的。例如:
personp;cint>>p.height;/*p、 高度不安全*/乘坐(p);/*无效*/如果p.height>12*12{ride(p);}/*fine*/}
正如我在12*12中指出的那样,编译器将不得不计算任意表达式,因此有些事情是不可判定的。但我可以忍受误报(或“不安全”模式下的误报)。我想知道Ada是否也支持类似的东西。不过,这似乎有点奇怪。就个人而言,我会将限制与类型集成,并允许基于这些限制的虚拟typedef。想象一下:typedef Person{height>140}作为SafePerson void ride(SafePerson p){…}
void ride(Person p)
  requires p.height > 140;
{
  //...
}