arraysrakuconscdr

perl6 functions similar to "car cdr cons" in scheme?


I really love perl6 and scheme. I am wondering if there are functions in perl6 that are similar to the "cons, car, cdr" functions in scheme? What I have been doing feels cumbersome:

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); }

Thanks.


Solution

  • Perl 6 lists/arrays are not linked list.
    However, the Pair type can be used to build linked lists, and provides the functionality of those three Lisp functions.

    Using nested Pairs

    A Pair represents a key-value pair. For example when iterating a Hash, you get a sequence of Pairs.

    If you think of a Pair as a cons cell, then you can build a linked lists à la Lisp as a Pair that has another Pair as its value, which in turn has another Pair as its value, and so on.

    Example:

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

    The => operator is right-associative, so that first line can also be written without the parentheses:

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

    If you wanted to declare the Lisp functions under their familiar names, it would look like this:

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

    Note, however, that there are no built-in convenience functions for doing list processing with such Pair-based linked lists. So if you wanted to do the equivalent of Scheme's length or append functions etc., then you'd have to write those functions yourself. All the built-in list processing routines assume normal Perl 6 lists or compatible Iterable types, which Pair is not.

    Using normal Perl 6 lists

    If you want to use normal Perl 6 lists/arrays as your data structure, but implement the behavior of the Lisp functions for them, I'd write it like this:

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

    Some comments: