当前位置: 首页 > 知识库问答 >
问题:

为什么要在Perl 6语法中使用原型规则?

云长恨
2023-03-14

这里有两个语法。一个使用原始令牌,一个不使用。他们都做了同样的事情。这些基本上是S05中“变量(非)插值”下的示例。在这个简单的例子中,他们都能够做同样的事情。

在哪些情况下,所有额外的输入都是合理的?proto标记在action类中有不同的方法,可能有一点好处。但是,您必须键入一些额外的内容才能获得该好处。

proto是否有一些特性使语法的其他部分更容易理解?

grammar NoProto {
    token variable   { <sigil> <identifier> }

    token identifier { <ident>+  }
    token sigil      { < $ @ % & :: > }
    }

grammar YesProto {
          token variable      { <sigil> <identifier> }

          token identifier    { <ident>+ }
    proto token sigil         {    *     }
          token sigil:sym<$>  {  <sym>   }
          token sigil:sym<@>  {  <sym>   }
          token sigil:sym<%>  {  <sym>   }
          token sigil:sym<&>  {  <sym>   }
          token sigil:sym<::> {  <sym>   }
    }

class Proto::Actions {
    method variable ($/) {
        say "found variable: " ~ $/;
        }
    method identifier ($/) {
        say "found identifier: " ~ $/;
        }
    method sigil ($/) {
        say "found sigil: " ~ $/;
        }
    method sigil:sym<$> ($/) {
        say "found sym sigil: " ~ $/;
        }
    }

my $variable = '$butterfuly';

say "------No proto parsing";
my $no_proto_match = NoProto.parse(
    $variable,
    :rule<variable>,
    :actions(Proto::Actions),
    );

say "------Yes proto parsing";
my $yes_proto_match = YesProto.parse(
    $variable,
    :rule<variable>,
    :actions(Proto::Actions),
    );

输出显示proto在action类中调用不同的方法:

------No proto parsing
found sigil: $
found identifier: butterfuly
found variable: $butterfuly
------Yes proto parsing
found sym sigil: $
found identifier: butterfuly
found variable: $butterfuly

共有3个答案

燕青青
2023-03-14

将备选方案拆分为proto和multi的一个好处是,您可以更可靠地扩展它。您可以将multi添加到从声明proto的语法继承而来的语法中的现有proto中,并且不需要列出所有可能的备选方案(在使用单个规则的情况下必须这样做)。

这意味着您甚至可以对同一语法进行多个独立的扩展,例如,通过混合几个规则,为不同的符号提供多个匹配。

这基本上就是Perl 6在定义自定义运算符时使用的机制:有一些规则用于匹配不同类型的运算符(如中缀、前缀、后缀等),并且声明一个新操作符从当前活动的操作符派生一个新语法,并为新操作符添加一个多候选。由于proto-token机制的可扩展性,一个脚本可以从几个互不了解的模块导入操作符。

毛宏达
2023-03-14

在actions类中使用它调用的方法有助于分离逻辑。除了语法之外,它与多重方法基本上是一样的。

(我写这篇文章是为了评估代码高尔夫的答案)

grammar Mathemania {
  token TOP               {   <cmd-list>           }

  token cmd-list          {   <cmd>+               }

  token cmd               {   <op>   <argument>?   }

  proto token op          { * }
  token op:sym<exp>       { e } # notice that the name doesn't have to match
  token op:sym<factorial> { f }
  token op:sym<root>      { r }
  token op:sym<ceil>      { c }
  token op:sym<floor>     { l }

  token argument          {  '(' ~ ')' <cmd-list>  }
}

class Calculate {
  method TOP      ($/) {   make $<cmd-list>.made   }
  method argument ($/) {   make $<cmd-list>.made   }

  method cmd-list ($/) {
    my $result = 2;

    $result = .made.($result).narrow for @<cmd>;

    make $result;
  }

  method cmd ($/) {
    if $<argument> {
      make $<op>.made.assuming( *, $<argument>.made );
    } else {
      make $<op>.made;
    }
  }

  method op:sym<exp>       ($/) { make -> \n, \e = 2 {  n ** e                   } }
  method op:sym<factorial> ($/) { make -> \n, \k = 2 {  [*] n, n - k + 1 ...^ 0  } }
  method op:sym<root>      ($/) { make -> \n, \r = 2 {  n ** (1/r)               } }
  method op:sym<ceil>      ($/) { make &ceiling }
  method op:sym<floor>     ($/) { make &floor   }

}

它还使得子类化语法可以在已经存在的标记旁边添加它的标记,子类化操作类也可以这样做。(试试看)

grammar Mathmania-Plus is Mathemania {
  token op:sym<negate> { n }
  token op:sym<abs>    { a }
}

class Calculate-Plus is Calculate {
  method op:sym<negate> ($/) { make &prefix:<-> }
  method op:sym<abs>    ($/) { make &abs }
}
梅玉堂
2023-03-14

从技术上讲,如果您不亲自指定,将为您制作一个原型。它基本上为特定的令牌创建多方法分派处理程序(就像它对方法所做的那样)。你通常不需要关心这些。

为什么要指定协议?我可以想到几个原因:

  1. 因为您希望令牌共享一些特性
  2. 因为要在分派之前或之后执行一些代码

是的,{ * }可能包含执行代码。裸露的无论表示分派给适当的候选人。用sub在更简单的情况下显示:

proto a(|) { say "before"; {*}; say "after" }
multi a(Int) { say "Int" }
multi a(Str) { say "Str" }
a 42; a "42"

显示:

before
Int
after
before
Str
after

希望这有帮助:-)

 类似资料:
  • 我对何时使用什么原语有点困惑。如果定义一个数字,如何知道使用、、或?我知道它们是不同的字节,但这是否意味着我只能对某个数字使用其中的一个呢? 所以简单地说,我的问题是,我什么时候使用上面列出的四个原语中的每一个?

  • 本文向大家介绍为什么要在R中使用set.seed?,包括了为什么要在R中使用set.seed?的使用技巧和注意事项,需要的朋友参考一下 set.seed的使用是为了确保我们获得相同的随机结果。如果我们为R或任何统计软件中的任何任务随机选择一些观测值,则它始终会产生不同的值,这是由于随机化而发生的。如果我们想保留在第一次随机选择时产生的值,则可以通过在随机化之后将它们存储在一个对象中来实现,或者可以

  • 为什么Java中的泛型可以处理类而不能处理基元类型? 例如,这个操作很好: 但这是不允许的:

  • 问题内容: 从Java 5开始,我们已经对原始类型进行装箱/拆箱,因此将其包装为,依此类推。 我最近看到许多新的Java项目(肯定要求JRE的版本至少为5,如果不是6的话)正在使用int而不是,尽管使用后者要方便得多,因为它具有一些用于转换的辅助方法到long的值等。 为什么有些人仍然在Java中使用原始类型?有什么切实的好处吗? 问题答案: 在Joshua Bloch的有效Java条款 5:“避

  • 问题内容: 在下面的代码中,我展示了我认为在golang中嵌入(提升方法的地方)和组合(提升方法的地方)之间的区别。 为什么要在golang中使用组合? 问题答案: 值得阅读有关“嵌入到有效Go中”的部分。 一个常见的示例是具有Mutex的结构/映射。 打字容易得多 而不是必须编写适当的包装器函数(重复的)或遇到困难 当你将永远做互斥领域的唯一事情就是访问方法(和在这种情况下) 当您尝试在嵌入式字

  • 问题内容: 我只是从Angular开始。阅读Google文档中的服务示例,我只是想知道为什么您会选择使用服务而不是将变量和函数正确地保留在控制器中? 在这种情况下,您何时选择使用服务? 问题答案: 我认为主要原因是: 在控制器之间持久并共享数据。 IE:您创建了一个从数据库中获取数据的服务,如果将其存储在控制器中,一旦更改为另一个控制器,数据将被丢弃(除非您将其存储在$ rootScope中,但这