Rascal 中的列表模式匹配

List pattern matching in Rascal

在 Haskell 中(在 Prolog / Erlang 中非常相似),我们可以在列表上定义一个长度函数:

length [] = 0
length (x:xs) = 1 + length xs

在 Rascal 中,我能够使用以下方法创建这样的定义:

int length([]) = 0;
int length([x,xs*]) = 1 + length(xs);

长度递归情况右边的“*”消失了。我知道这可能是有原因的,但我想不通。在 Rascal 中使用模式匹配在列表上定义递归函数是否有更好的方法?

我想解决你问题的多个方面:

  1. 你的 Rascal 版本看起来不错。 Rascal 比 Haskell 具有更通用的列表模式匹配:不止一个变量可以匹配多个元素,因此列表模式中的每个 "list variable" 都必须用 * 标记以指示仅那。
  2. 我们正处于从后缀 * 到前缀 * 的过渡阶段。所以第二条规则可以(以后也应该)写成:

    int length([x,*xs]) = 1 + length(xs);

  3. 您可能想探索可用于编写各种类似折叠函数的 reducer 表达式

    int length(list[int] xs) = ( 0 | it + 1 | x <- xs );

    它由三部分组成:

    • 初始值(0);内置变量 it 设置为此初始值。
    • 一个累加结果的表达式,可能用到it,这里:it + 1。它具有 it = it + 1.
    • 的效果
    • 生成列表元素的枚举。
  4. 更一般的(比简单的 head/tail)模式匹配示例如下:
    • [*x, a] : 匹配列表末尾的元素
    • [*x, *x] : 将列表分成两等份
    • [*a, x, *b, x, *c] : 找到两个重复的元素
  5. 一个绑定列表变量绑定一个完整的列表,你可以像使用任何其他指向列表的变量一样使用它,但是如果你想将它拼接在规则的右侧,你会得到一个更对称的观点:int length([x,*xs]) = 1 + length([*xs]);,当然这也是泛化的,所以这样也是可以的:[*xs, 2, *xs] 其中*操作符只是去掉了一层列表嵌套。