模仿引号

楽土

我对缩短代码的追求进展顺利。有一件事还是挺啰嗦的,那就是对象创建。为了让管道充满生命,我们需要 Proc::Async 的实例。

my $find = Proc::Async.new: </usr/bin/find /tmp>;

正如我前面所展示的操作符是去样板化。我们将需要那个目前要去 .new 的参数列表。如果能把其他的东西减少到只有两个字母,那就更好了。让我们定义一个子例程前缀来做到这一点。

sub prefix:<px>(List:D \l) is looser(&infix:<,>) { say ‚Proc::Async.new: <‘, l.Str, ‚>‘; };

px</usr/bin/find /tmp>; # OUTPUT Proc::Async.new: </usr/bin/find /tmp>
px ‚/usr/bin/find‘, ‚/tmp‘; # OUTPUT Proc::Async.new: </usr/bin/find /tmp>

通过使用 is looser(&infix:<,>),我们告诉编译器创建一个 List,然后用一种有趣的语法调用名为 px 的子例程。通过这样做,我们模仿了用于实现 qx 的引号结构,并且能够留下一个空格。不过有一个问题。

px«/usr/bin/find /tmp»;

# OUTPUT:
# ===SORRY!=== Error while compiling /home/dex/projects /raku/lib/raku-shell-piping/EVAL_0
# Two terms in a row
# at /home/dex/projects/raku/lib/raku-shell-piping/EVAL_0:1
# ------> px«/usr/⏏bin/find /tmp;
#     expecting any of:
#         infix
#         infix stopper
#         statement end
#         statement modifier
#         statement modifier loop

这里的 grammar 似乎很混乱。既然有一种替代方法可以用内插的方式列出引号,我将继续进行错误修复。

我通过 R#3799 的唠叨取得了成果,并提供了一个解决这个问题的办法。

class C {
    has $.state is rw;
}

my \px = C.new;

multi postcircumfix:<{ }>(C:D, $s, Bool :$adverb = False) {
    Proc::Async.new: $s;
}

multi postcircumfix:<{ }>(C:D, @a, Bool :$adverb = False) {
    Proc::Async.new: @a;
}

multi infix:<|»>(Proc::Async:D $l, Proc::Async:D $r, :$different-adverb = "non-given") {
    dd $l;
    dd $r;
}

px<ls>;
px«ls»;
my $a = 42;
px<ls 1 2 3 $a>;
px«ls $a»;
px«ls $a»:adverb;

px{'foo' ~ 41.succ};

px«ls $a»:adverb |» (px«sort»:adverb) :different-adverb(42);

这提供了我所需要的所有模拟 qx 的各种形式。C 的实例被用作编译器的占位符,它的状态可以是全局的,适用于所有对 postcircumfix:<{ }>(C:D,...) 的调用。这在以后可能会很方便。

Shell::Piping 到目前为止已经引起了 3 个 bug 报告。我确实觉得自己是第一个踩到这个沼泽地的人。如果我没能成功,请抱着我的朋友们删除我的浏览器历史记录。

comments powered by Disqus