Функции perl6, аналогичные "car cdr cons" в схеме?

Я очень люблю 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); }

Благодарю.

2 ответа

Решение

Списки / массивы Perl 6 не являются связанными списками.
Тем не менее Pair Тип может использоваться для создания связанных списков и обеспечивает функциональность этих трех функций Lisp.

Использование вложенных Pair s

Pair представляет пару ключ-значение. Например, при итерации Hash, вы получите последовательность Pair s.

Если вы думаете о Pair как ячейка "против", то вы можете построить связанные списки в виде 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 или добавить функции и т. Д., То вам придется написать эти функции самостоятельно. Все встроенные процедуры обработки списков предполагают нормальные списки 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 ключевое слово необязательно; Результат последнего оператора функции возвращается автоматически.

Вот еще один набор функций, схожий с вашими оригиналами и использующий префиксные операторы для 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) }

Они обеспечивают почти полный синтаксис, если хотите.

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;
Другие вопросы по тегам