Где мой оператор Perl 6 пошел после того, как я определил более конкретный мульти?

Я играю с этой маленькой штукой, где набор может выступать в качестве дополнения, переворачивая тесты. Чтобы сделать эту работу, я создаю специальные версии операторов членства.

class Complement {
    has $.set;
    }

multi infix:<∈> ( $a, Complement:D $c ) { $a ∉ $c.set   }
multi infix:<∉> ( $a, Complement:D $c ) { $a ∈ $c.set }

my $set = (1, 2, 3).Set;
my $c = Complement.new: set => $set;

put 3 ∈ $set;
put 4 ∈ $c;

С моим определением infix:<∉> другой, более общий, кажется, исчез. Других кандидатов нет:

True
Cannot resolve caller infix:<∉>(Int, Set); none of these signatures match:
    ($a, Complement:D $c)
  in sub infix:<∈> at /Users/brian/Desktop/complement.p6 line 11
  in block <unit> at /Users/brian/Desktop/complement.p6 line 18

Что мне нужно сделать, чтобы сохранить предыдущие определения с разными сигнатурами?

Ответ 1

Это потому, что &infix:<∈> является мульти, while &infix:<∉> не является:

$ perl6 -e '&infix:<∈>.candidates.head.multi.say'
True
$ perl6 -e '&infix:<∉>.candidates.head.multi.say'
False

Когда вы определили свой multi &infix:<∉>, вы затенены only &infix:<∉> из основного, и именно поэтому вы видите только своего кандидата.

Вероятно, мы можем обнаружить такую ситуацию и потребовать от пользователя предоставления явного proto чтобы уточнить, что они означают. Я подал это как R # 1530. И я бы сказал, что такие различия, что один оп является multi, а другой является only частью более широкого вопроса наличия согласованного ядра; Я добавил его в качестве комментария к RT # 130020 и упомянул проблему в наших документах на D # 1783.

Вы могли бы определить свой собственный op так (если предложение в R#1530 реализовано, proto будет требоваться, в настоящее время это не так):

proto infix:<∉> (|) {*}
multi infix:<∉> ($a, Complement:D $c) { $a ∈ $c.set }
multi infix:<∉> (|c) { &CORE::infix:<∉>(|c) }

Я могу только догадываться, что вы пытаетесь закодировать, но подумал, что я упоминал об этом, потому что вы должны учитывать это в своем творчестве: отрицательные операторы определяются как not A (op) B, а не A (not(op)) B Эта небольшая разница имеет влияние, когда дело доходит до Junctions:

$ perl6 -e 'say 2 ≠ 2|4'
False

Если бы он был определен как отрицаемый op, применяемый к каждому операнду, вышеупомянутое было бы эквивалентно (2 ≠ 2 or 2 ≠ 4) и всегда было бы True, что часто не то, что имел бы в виду программист, следовательно, почему вычислено как not (2 == 2 or 2 == 4)


Чтобы ответить на комментарии Jarrod о OP: subs (включая мутации грамматики, сделанные объявлением пользовательских операторов), являются лексическими, поэтому, если вы завернули объявление в блок BEGIN, пользовательский op будет привязан к этому блоку.

И причина, по которой он работал в REPL, состоит в том, что на самом деле есть ошибка (RT # 131900), где пользовательские операционные системы теряются между линиями REPL, так же, как и с блоком BEGIN, к моменту вызова с аргументами, предназначенными для основных кандидатов, пользовательский мультисъемка больше не был в сфере охвата.