2017-01-22 29 views
8

Представьте себе ряд сложных грамматик, представленных в виде ролей, хотя этот простой пример достаточно, чтобы показать конфликт:Должен ли Perl 6 распутать включение одной и той же роли из разных источников?

role Alpha { 
    token alpha { :i <[A..Z]> } 
    } 

role Digit { 
    token digit { <[0..9]> } 
    } 

role Either 
    does Alpha 
    does Digit { 
    token either { <alpha> | <digit> } 
    } 

grammar Thingy 
    does Either 
    does Alpha 
    { 
    token TOP { <alpha> <either>* } 
    } 

my $match = Thingy.parse('1a3'); 
dd $match; 

Это не работает, потому что Perl 6 не распутать отношения, чтобы выяснить, что конфликт на самом деле то же самое из того же источника:

Метод «альфа» должен быть решен класса Thingy, поскольку она существует в нескольких ролях

Но, читая S14, я вижу:

Роль не может наследоваться от класса, но может состоять из других ролей. Однако этот состав «крона» не оценивается до времени композиции композиции. Это означает, что если две роли приносят один и тот же crony, нет конфликта - это похоже на то, что класс потянул на себя роль crony и соответствующие роли не сделали. Роль никогда не может противоречить самому себе, независимо от способа его включения.

Я читал, что означает, что роли применяются как можно позже, так что класс Thingy сможет распутать, что Alpha входит в двух различных частей. Я полагал, что это сработает как создание списка всех ролей, которые будут составлять последний класс, а затем применить этот список только к конечному классу. Таким образом, что-то вроде Either будет смешивать только те вещи, которые он определил, и будет полагаться на более позднюю композицию, чтобы ввести Alpha.

Я столкнулся с этим, когда я пытался реализовать грамматики для различных (IETF) RFC. Многие из них ссылаются на грамматики из других RFC, что делает невозможным разрешение Perl 6 наследованием на C3. Итак, я понял, что роли будут отключать отношения. По-видимому, это не так.

+0

Имеет ли это что-то особенное для грамматик? Следующие не выполняются одинаково (и как ожидалось): 'perl6 -e 'role Foo {method bar {}}; role Baz {method bar {}}; class My :: Грамматика {также делает Foo; также Баз; } '' В противном случае вы можете, конечно, решить его самостоятельно (это указано в документах для ролей):' token Host {$ = <Грамматика :: IETF :: URI :: RFC3986 :: host> [' : '<.port>]? } ' – ugexe

+0

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

+2

Ответ на вопрос в заголовке «Да, это должно». –

ответ

3

Да, Perl 6 должен иметь возможность распутать включение одной и той же роли из разных источников.

Простые definition s из более role являются:

Роль инкапсулирует некоторую часть поведения или состояния, которые могут быть распределены между классами.

или

Роль это имя для дискретного набора поведений.

Итак, допустим, у нас есть Floatable поведение для объектов, которые могут быть плавали на воде, и Sailable поведение для объектов, которые могут быть плавал. Естественно, что объекты, которые можно отплыть, можно всплывать. A Sloop является, естественно, плавающим и плавающим. Нет конфликта в том, что такой жеFloatable поведение передается как Floatable, так и Sailable ролями.

В Perl, это работает, как ожидалось (он работает с Moose а):

#!/usr/bin/env perl 

use v5.24; # why not 
use warnings; 

package Floatable { 
    use Moo::Role; 
    sub float { say "float" } 
} 

package Sailable { 
    use Moo::Role; 
    with 'Floatable'; 
    sub sail { $_[0]->float; say "sail" }; 
} 

package Sloop { 
    use Moo; 
    with qw(Floatable Sailable); 
} 

my $s = Sloop->new; 

$s->sail; 

Такое поведение является интуитивно очевидным.

Одна проблема, я заметил, глядя на Perl6 documentation for roles является отсутствие простой, один приговор определения:

Роли в некоторых отношениях аналогичны классам, в том, что они представляют собой набор атрибутов и методов. Они отличаются тем, что роли также предназначены для описания только частей поведения объекта и того, как роли применяются к классам. Или, говоря иначе, классы предназначены для управления объектами, а роли предназначены для управления поведением и повторным использованием кода.

...

Роль приложения существенно отличается от наследования классов. Когда роль применяется к классу, методы этой роли копируются в класс. Если к одному классу применяются несколько ролей, конфликты (например, атрибуты или не-несколько методов с одним и тем же именем) вызывают ошибку времени компиляции, которая может быть решена путем предоставления метода с тем же именем в классе.

По-видимому, когда perl6 встречает две роли, которые обеспечивают точно такое же поведения, он считает, что это как конфликт в пути, я считаю неразумным.

Обратите внимание на тонкое различие в следующем примере:

#!/usr/bin/env perl 

use v5.24; # why not 
use warnings; 

package Floatable { 
    use Moo::Role; 
    sub float { say "float" } 
} 

package Sailable { 
    use Moo::Role; 
    sub float { say "floating bonds to finance journey "} 
    sub sail { $_[0]->float; say "sail" }; 
} 

package Sloop { 
    use Moo; 
    with qw(Floatable Sailable); 
} 

my $s = Sloop->new; 

$s->sail; 

В этом случае конфликт следует ожидать, потому что две различные роли хотят требовать, чтобы обеспечить те же модели поведения.