Wait the light to fall

Deconstructing Simple Grammars

焉知非鱼

去年我写了一个鸡蛋定时器,它的解析命令行参数类似于 GNU sleep。我对这个解析器的严格形式很满意,如下。

my Seconds $to-wait = @timicles»\
    .split(/<number>/, :v)\
    .map(-> [$,Rat(Any) $count, Str(Any) $unit] --> Seconds { %unit-multipliers{$unit} * $count })\
    .sum;

它只做了几件简单的事情,而且是一件接着一件做。带有动作类的 grammar 就显得矫枉过正了。我不满意用 split 的能力来返回带有零件的针。它肯定不会提高可读性。

经过相当多的迭代(并踩到了一个 bug),我想出了一个使用 Str.match 代替的方法。如果我把每个 Match 对象转换成 Hash,我就可以在一个尖号块的签名中使用解构

my Seconds $to-wait = @timicles»\
    .match(/<number> <suffix>+/)».hash\ # the +-quatifier is a workaround
    .map(-> % ( Rat(Any) :$number, Str(Any) :$suffix ) { %unit-multipliers{$suffix} * $number })\
    .sum;

我可以不使用位置参数,而是使用命名的参数,这些参数对应于匹配参数中命名正则表达式。

即使是在这样一小段代码中,事情也会变得有条不紊。超方法调用摆脱了简单的循环。精心设计的内置类型允许在没有临时变量负载的情况下进行签名解构。这几乎就像某些语言设计者的目标是制造一种最优雅的语言一样。

by gfldex.