5

我真的很喜欢 perl6 和方案。我想知道 perl6 中是否有类似于方案中的“cons、car、cdr”函数的函数?我一直在做的事情感觉很麻烦:

sub cons($a, $aList) { return flat($a, $aList); } # sometimes flat is undesired;
sub car($aList) { return first($aList); }
sub cdr($aList) { return tail($aList.elems - 1); }

谢谢。

4

2 回答 2

9

Perl 6 列表/数组不是链表。
但是,该Pair类型可用于构建链表,并提供这三个 Lisp 函数的功能。

使用嵌套Pair

APair代表一个键值对。例如,当迭代 a 时Hash,您会得到一个 s 序列Pair

如果您将 aPair视为一个 cons 单元格,那么您可以构建一个链表 à la Lisp 作为 a Pair,它有另一个Pair作为其值,而后者又将另一个Pair作为其值,依此类推。

  • =>运算符(Pair构造函数)履行cons的角色。
  • .key方法完成了car的作用。
  • .value方法完成了cdr的角色。

例子:

my $l = (1 => (2 => (3 => (4 => (5 => Nil)))));
say $l.key;    # 1
say $l.value;  # 2 => 3 => 4 => 5 => Nil

运算符是右结合的=>,所以第一行也可以写成不带括号:

my $l = 1 => 2 => 3 => 4 => 5 => Nil;

如果你想用它们熟悉的名字来声明 Lisp 函数,它看起来像这样:

sub cons ($x, $y)  { $x => $y }
sub car  (Pair $y) { $y.key   }
sub cdr  (Pair $y) { $y.value }

但是请注意,没有内置的便利函数可用于使用此类Pair基于 - 的链表进行列表处理。因此,如果您想做相当于 Scheme 的长度附加函数等,那么您必须自己编写这些函数。所有内置列表处理例程都假定正常的 Perl 6 列表或兼容Iterable类型,但Pair事实并非如此。

使用普通的 Perl 6 列表

如果你想使用普通的 Perl 6 列表/数组作为你的数据结构,但是为它们实现 Lisp 函数的行为,我会这样写:

sub cons ($x, $y) { $x, |$y  }
sub car  (@y)     { @y[0]    }
sub cdr  (@y)     { @y[1..*] }

一些评论:

  • flat我没有使用,而是使用|运算符将​​ 的元素$y滑入外部列表。
  • first函数不符合您在代码中的预期。它用于搜索列表。它将第一个参数(在您的情况下$aList)解释为谓词,其余参数(在您的情况下没有)解释为要搜索的列表,因此在您的情况下它总是返回Nil
    要返回列表的第一个元素,您可以使用[ ]位置下标运算符,就像我在这里所做的那样。
  • return关键字是可选的;自动返回函数最后一条语句的结果。
于 2016-09-11T17:55:38.677 回答
1

这是另一组功能,类似于您的原始功能,并为 car / cdr 使用前缀运算符:

sub prefix:<car>(List $l) is tighter(&infix:<xx>) { $l.head }
sub prefix:<cdr>(List $l) is tighter(&infix:<xx>) { $l.tail(*-1).list }
sub cons($item, List $l) { ($item, |$l) }

如果您愿意,它们提供了一种几乎是 lisp-ish 的语法。

my @l = (1, 2, 3, 4);
my $l = |@l;

say "Array";
say "car: ", (car @l).perl;
say "cdr: ", (cdr @l).perl;

say "List";
say "car: ", (car $l).perl;
say "cdr: ", (cdr $l).perl;

say "Literal";
say "car: ", (car (4, 3, 2, 1)).perl;
say "cdr: ", (cdr (4, 3, 2, 1)).perl;

say "cons: ", (cons car $l, cdr $l).perl;
于 2017-05-28T21:59:53.227 回答