15

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

可以使用enums 和unions 来模拟它们(如在 C、C++、...更多?),但这很快就会变得麻烦和丑陋,如果您在模式匹配中忘记了一个案例,编译器也不会警告您或者(更可能,也更危险)当“以错误的方式”访问联合时,即Left当它实际上是一个值时你要求一个值的字段Right(你得到的是对发生的位的毫无意义的重新解释在那里)。

我听说Pascal 有类似标记联合的东西,而Cyclone 语言也支持标记联合。维基百科还提到了 Ada 和 Algol。还有其他语言吗?

(如果您从未听说过代数数据类型,您可以阅读“什么是函数式语言中的'模式匹配'?”的答案以获得出色的介绍)。

4

5 回答 5

13

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

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

type Shape =
| Circle of float
| EquilateralTriangle of double
| Square of double
| Rectangle of double * double

let area myShape =
    match myShape with
    | Circle radius -> Math.PI * radius * radius
    | EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
    | Square s -> s * s
    | Rectangle (h, w) -> h * w

可以大致翻译成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关键字用于让编译器警告您,以防您忘记表达式case中的任何内容。match

于 2010-10-19T12:37:53.823 回答
10

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

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);
}
于 2013-01-18T18:45:34.267 回答
8

逻辑编程语言 Mercury 称它们为可区分联合。Prolog 中嵌入的约束语言 CHR也有它们,但它们完全是可选的,通用 Prolog 术语是默认类型。

于 2010-10-18T20:43:20.887 回答
6

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.
于 2010-10-18T20:37:32.883 回答
3

我认为Whiley有资格。Whiley 有记录类型(即产品)和类型联合(即总和),因此。

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

于 2013-07-31T09:46:32.240 回答