В ответ на ваш вопрос я изобрел то, что назову четырехэтапным перенаправлением. Это включает четыре шага:
Образец соответствует составным структурам данных, над которыми нужно иметь контроль;
Приведение совпадающих структур данных к новому типу;
Образец соответствует последующим подпрограммам, вызываемым для нового типа;
Перенаправьте совпадающие подпрограммы по желанию.
Я играл с различными способами реализации этого 4-этапного перенаправления, некоторые из которых использовали объектно-ориентированный подход, другие просто использовали функции. Ниже приведен кратчайший путь к решению, которое я придумал для вашего конкретного примера:
role Point { # <-- Make `role`
has $.x; has $.y;
multi method sum(Point $p) { Point.new: :x($!x + $p.x) :y($!y + $p.y) }
multi method COERCE ($_) { $_ but Point } # <-- Hook `sum`
multi method sum { self.List[0].sum: self.List[1] } # <-- Reroute `sum`
}
my $p1 = Point.new: :8x :3y;
my $p2 = Point.new: :1x :9y;
say Point($p1, $p2).sum; # OUTPUT: «Point.new(x => 9, y => 12)»
Давайте вспомним четыре шага перемаршрутизации, с которых я начал, и то, как я их реализовал выше:
Образец соответствует составным структурам данных, над которыми нужно иметь контроль;
В say Point($p1, $p2).sum;
я вставил вызов Point(...)
. Поскольку Point
— это тип, это запускает протокол принуждения Раку. Это один из способов начать процесс сопоставления с образцом. Одной частью протокола является вызов метода COERCE
типа в некоторых сценариях. Итак, я добавил к вашему типу метод multi method COERCE...
, и он вызывается. В этом случае фактический аспект соответствия шаблону этого вызова минимален — всего $_
— но я немного уточню его в другой версии этого решения ниже.
Приведение совпадающих структур данных к новому типу;
Это код $_ but Point
. Смешивание в Point
является минимальным, но достаточным принуждением. (Обратите внимание, что это может быть написано наоборот — Point but $_
, и оно все равно будет работать.) Чтобы это работало, я изменил декларатор типа для Point
с class
на role
.
Образец соответствует последующим подпрограммам, вызываемым для нового типа;
Это объявление multi method sum
.
Перенаправьте совпадающие подпрограммы по желанию.
Это код self.List[0].sum: self.List[1]
.
В качестве иллюстрации более конкретного сопоставления шаблонов на шаге 1:
multi method COERCE (List $_ (Point, Point)) { $_ but Point }
Если бы вы использовали эту 4-ступенчатую перемаршрутизацию, то шаблоны сигнатур, подобные приведенным выше, вероятно, были бы очень разумными.
Идиома для облегчения более лаконичного кода для шага 4:
multi method sum ($_: ;; $/ = .List) { $0.sum: $1 }
Это выглядит невероятно безобразно. И для чего? Почему я включил его? Ну, я надеюсь, вы видите потенциал, на который он намекает. Это действительно не имеет ничего общего с вашим вопросом или моим ответом. Но я не следую рациональным правилам в отношении того, когда я собираюсь чем-то поделиться. Я надеюсь, что смогу очаровать, в частности, вас, @codesections, и всех, кто читает это, кто может читать мои мысли.
Во-первых, к сожалению, большинство людей не осознают, что Capture
s являются важной и малоиспользуемой инновацией в области эргономики в Raku. Capture
предназначен не только для записи аргументов. Это не просто родительский класс Match
. Это общий тип вложенной структуры данных.
Во-вторых, аналогично, $/
— это не просто текущая переменная Match
. Это также очень удобная функция автодеструкции для Capture
s, то есть автоматическая деструктуризация общих вложенных структур данных.
Я обдумывал, как лучше всего ввести в культуру раку следующее, но я считаю, что было бы здорово иметь соответствующие элегантные / практичные / нюансированные функции, соответствующие трем переменным пунктуации $_
, $/
и $!
.
Я назвал свое соломенное предложение (в уме) «Данные», хорошо? Обратите внимание, как это три слова. За последние несколько лет я обработал массу деталей, но я надеюсь, что вы сможете интуитивно представить, куда мы могли бы отправиться, если бы пошли по пути, который я предлагаю. Я действительно должен написать это вкратце; это странное приложение к этому ответу SO является авансовым платежом.
person
raiph
schedule
03.04.2021