Функции 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;