rakulang, dartlang, nimlang, golang, rustlang, lang lang no see

Raku is a match for *

焉知非鱼

Raku Is a Match for *

PimDaniel 提出了一个有趣的问题。

我如何在匹配时测试 match is True : 这不起作用。

if my ($type,$a,$b,$c) = ($v ~~ /^ ('horiz'|'vertic') '_' (\d+) '_' (\d+) '_' (\d+) $/)>>.Str { ... }

好吧,我分2次做了1/捕捉并测试匹配,2/将匹配转换为Str。

没有得到及时的回答,完全没有改进。我也找不到一个好的方法来快速完成这个任务。事实上我花了一个小时才破解这个螺母。这里的主要问题是,一个失败的匹配会产生 .Str 会抱怨的 Nil。所以让我们把 if 的布尔检查和转换为 Str 的过程分开。

my $a = '1 B';

if $a ~~ /(<digit>) \s (<alpha>)/ -> $_ {
    my ($one, $B) = .deepmap: *.Str;
    say "$one $B";
}
# OUTPUT: 1 B

通过将条件表达式的结果强行放入主题中,我们可以在匹配的结果上运行任何方法,但前提是 Match.bool 返回 true。我没有 CS* 学位,但如果 Raku-signatures 不会变成 turing complete,我会非常惊讶。

if $a ~~ /(<digit>) \s (<alpha>)/ -> Match (Str() $one, Str() $B) {
    dd $one;
    dd $B;
}
# OUTPUT: "1"
          "B"

if 块的签名将 Match 胁迫为一个列表。我们选择其中的两个元素,并将这些元素胁迫为 Str。当然,我们可以根据捕获的位置来强制到任何我们喜欢的东西。

Raku 中的 Regexes 被编译成相同的字节码,然后程序的其余部分。事实上,语法只是一个具有有趣语法的类。这就是为什么我们可以轻松地在 regex 里面运行Raku 代码。这意味着我们可以把整个程序从内部翻出来。

my @a = <1 B 3 D 4>;
my @b;

my $hit;

for @a -> $e {
    @b.push: ($e ~~ /(<alpha>) || { next } /).Str;
}

say @b;
# OUTPUT: [B D]

在这里,如果匹配不成功,我们就跳过 .push,用 next 跳过循环体的其余部分。我们可以在 regex 内部发出任何控制异常。这意味着我们可以将整个过程粘在一个 sub 中,然后从 regex 中返回我们正在寻找的值。

sub cherry-pick-numeric(Str $matchee) {
    $matchee ~~ m/(<digit>) && { return .Numeric }/;
    Empty
}

@b = do .&cherry-pick-numeric for @a;

dd @b;
# OUTPUT: Array @b = [1, 3, 4]

Raku 已经酝酿了10年。这是一个巨大的任务。现在,困难的部分来了。我们必须从那庞大的语言中找到所有好的惯用法。好东西会降临到那些等待的人身上(IRC上)。

*) 阅读。不要相信我写的任何东西。你已经被警告了。

更新一下。

我以真正的懒惰方式,想出了一个办法,在本该完成的工作之后,把匹配变成一个惰性列表。

$a = '1B3D4';

my \ll := gather $a ~~ m:g/
      [ <alpha> && { take $/<alpha>.Str } ]
    | [ <digit> && { take $/.<digit>.Numeric } ]
    | [ { say 'step' } ]
/;
say ll[0];
say ll[3];
# OUTPUT: 1
          step
          step
          step
          D

技巧是用 :g 副词强制匹配一直运行到字符串的末尾。这个运行将被 take 打断(通过抛出 CX::Take),当从 gather 返回的 Seq 中询问下一个值时再继续。我不知道这是否是有效的内存思想。可能会有一个 Match 实例为每个 take 保留在身边。

原文链接: https://gfldex.wordpress.com/2021/03/11/raku-is-a-match-for/