Language agnostic 函数语言之外的代数数据类型?

Language agnostic 函数语言之外的代数数据类型?,language-agnostic,programming-languages,functional-programming,algebraic-data-types,Language Agnostic,Programming Languages,Functional Programming,Algebraic Data Types,哪些不只是函数的语言有代数数据 类型(或类似的东西)和模式匹配?我还对多范式语言感兴趣——我知道Ocaml和F#是添加了OO的ML方言,因此它们继承了ML的代数数据类型 < >可以使用 EnUM >和联合< /Calp> S(如C,C++,…更多)来模拟,但是这很快会变得麻烦和丑陋,如果你忘记了模式匹配的情况下,编译器不能警告你,或者当访问联盟“错误的方式”时,(更可支持,更危险)。也就是说,当字段实际上是右值时,您请求一个左值的字段(然后您得到的是对碰巧存在的位的无意义的重新解释) 我听说了,

哪些不只是函数的语言有代数数据 类型(或类似的东西)和模式匹配?我还对多范式语言感兴趣——我知道Ocaml和F#是添加了OO的ML方言,因此它们继承了ML的代数数据类型

< >可以使用<代码> EnUM<代码> >和<代码>联合< /Calp> S(如C,C++,…更多)来模拟,但是这很快会变得麻烦和丑陋,如果你忘记了模式匹配的情况下,编译器不能警告你,或者当访问联盟“错误的方式”时,(更可支持,更危险)。也就是说,当字段实际上是
值时,您请求一个
值的字段(然后您得到的是对碰巧存在的位的无意义的重新解释)

我听说了,支持工会的人也这么说。维基百科也提到了Ada和Algol。还有其他语言吗


(如果您从未听说过代数数据类型,您可以阅读一篇精彩的介绍)。

Erlang有一个动态类型系统,因此它不提供您引用的任何保证,但Erlang代码看起来确实像代数类型系统的产物:

count([]) -> 0;
count([H|T]) -> 1 + count(T).

length({rect, X, Y}) -> math:sqrt(X*X + Y*Y);
length({polar, R, _A}) -> R.

逻辑编程语言Mercury调用它们。约束语言CHR也嵌入在Prolog中,但它们是完全可选的,一般的Prolog术语是默认类型。

在Scala中,您通常会使用
case类
es来模拟在真正的蓝色函数语言(如ML和Haskell)中发现的代数数据类型

例如,以下F#代码(取自):

可以大致转换为Scala,如下所示:

sealed abstract class Shape
case class Circle(radius: Float) extends Shape
case class EquilateralTriangle(side: Double) extends Shape
case class Square(side: Double) extends Shape
case class Rectangle(height: Double, width: Double) extends Shape

def area(myShape: Shape) = myShape match {
  case Circle(radius) => math.Pi * radius * radius
  case EquilateralTriangle(s) => math.sqrt(3.0) / 4.0 * s * s
  case Square(s) => s * s
  case Rectangle(h, w) => h * w
}

上面的
sealed
关键字用于让编译器在您忘记
match
表达式中的任何
case
时向您发出警告。

在Mozilla语言中,代数数据类型和模式匹配是重要的概念。语法也相当不错。考虑下面的简单程序:

static PI: f32 = 3.14159;

enum Shape {
    Circle(f32),
    Rectangle(f32, f32),
    Point
}

fn area(shape: Shape) -> f32 {
    match shape {
        Point                    => 0.0
        Circle(radius)           => PI * radius * radius,
        Rectangle(width, height) => width * height,
    }
}

fn main() {
    let radius = 4.0;
    let circle = Circle(radius);
    let area = area(circle);
    println!("The area of a circle with radius {} is {}", radius, area);
}
我想那是符合条件的。 Whiley有记录类型(.ie.乘积)和类型联合(即sum),因此


匹配似乎只能在类型上进行,即,您可以询问具有联合类型的值是否是联合中的一种类型,然后该值被“重新类型化”,您可以访问您检查的类型的字段。

谢谢-我不知道逻辑语言,所以我可能自己不会学这个。这两种语言都是研究语言。LP社区从它的FP近亲那里借用了很多东西。语法也相当不错-是的,除了花括号和分号。@Malcolm我想否决你的评论;)---过大的噪音很少有帮助,大括号甚至不能说明它们关闭了哪个块!if..fi或do..od或beginX…endX的旧样式至少是信息型的,使用大括号,我们往往会以占用空间的楼梯结束,这对可读性完全没有帮助。使用自动代码格式,它们是信息型的。要确定哪个大括号与块相对应,只需在垂直线上查找页面。不管风格如何,理解范围的开始和结束都会带来认知开销。如果使用“beginX/endX”,则必须命名所有作用域,并按名称记住所有作用域,以导航代码段。这就是我所看到的增加噪音——额外的认知开销(命名范围),没有任何额外的好处。在看到一些Ada代码之前,我一直在考虑使用关键字创建代码块(如if、fi、begin、end)。大括号的优点是不会增加字符噪波。在阅读代码时,我们不仅希望代码在某种层次结构中得到明确定义(这就是我们缩进的原因),我们还希望我们的重点是创建什么,而不是一堆begin/end/procedure/等等。许多花括号语言的问题是,使用它们的语言鼓励使用具有许多嵌套控件特性的长函数。相反,该语言应该支持诸如第一类函数、类型推断(关于函数返回和参数)等,以鼓励更短的函数。
static PI: f32 = 3.14159;

enum Shape {
    Circle(f32),
    Rectangle(f32, f32),
    Point
}

fn area(shape: Shape) -> f32 {
    match shape {
        Point                    => 0.0
        Circle(radius)           => PI * radius * radius,
        Rectangle(width, height) => width * height,
    }
}

fn main() {
    let radius = 4.0;
    let circle = Circle(radius);
    let area = area(circle);
    println!("The area of a circle with radius {} is {}", radius, area);
}