【问题标题】:perl6 functions similar to "car cdr cons" in scheme?perl6 功能类似于方案中的“car cdr cons”?
【发布时间】:2016-09-11 17:24:53
【问题描述】:

我真的很喜欢 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); }

谢谢。

【问题讨论】:

    标签: arrays raku cons cdr


    【解决方案1】:

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

    使用嵌套的Pairs

    Pair 代表一个键值对。例如,在迭代Hash 时,您会得到Pairs 的序列。

    如果您将 Pair 视为 cons 单元格,那么您可以将链表 à la Lisp 构建为 Pair,其中有另一个 Pair 作为其值,而另一个 Pair 作为其值它的值,等等。

    • => 运算符(Pair 构造函数)履行缺点的角色。
    • .key 方法完成了汽车的角色。
    • .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 的 lengthappend 函数等,那么您必须自己编写这些函数。所有内置列表处理例程都假定正常的 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..*] }
    

    一些cmets:

    • 我没有使用flat,而是使用| operator$y 的元素滑入外部列表。
    • first 函数没有按照您在代码中的预期执行。 它用于搜索一个列表。它将第一个参数(在您的情况下为 $aList)解释为谓词,并将其余参数(在您的情况下为无)解释为要搜索的列表,因此在您的情况下,它始终返回 Nil
      要返回列表的第一个元素,您可以改用 [ ] positional subscripting operator,就像我在此处所做的那样。
    • return 关键字是可选的;自动返回函数最后一条语句的结果。

    【讨论】:

    • "自动返回函数的最后一条语句。" 如何返回语句?你的意思是最后一个表达式的结果吗?
    • @KeithThompson:最后一条语句被视为表达式,并返回其值。例外情况是,当最后一条语句是块结构时(如for 循环),如果到达函数末尾,则返回Nil
    【解决方案2】:

    这是另一组函数,与您的原始函数类似,并且使用 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 2010-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多