MAIN()参数中的字符串匹配

时间:2019-01-24 02:21:53

标签: perl6

我想使用字符串匹配将参数限制为MAIN()。 这有效:

sub MAIN(
    Str :$r where * eq any(< aaa bbb ccc >) = "bbb"
) { say $r }

$ perl6 tb.p6 -r="ccc"
ccc

但这不是:

sub MAIN(
   Str :$r where * ~~ m:i/< aaa bbb ccc >/ = "bbb",
) { say $r }

$ perl6 ta.p6 -r="ccc"
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
  in whatevercode  at ta.p6 line 2
Usage:
  ta.p6 [-r=<Str where { ... }>] 

2 个答案:

答案 0 :(得分:7)

最大的问题是您同时使用*m来制作WhateverCode lambda。

m/…/$_中发生的任何情况匹配。
这实际上发生在~~之外。

如果您仅使用m/…/,那么它将有效

sub MAIN(
    Str :$r where m:i/< aaa bbb ccc >/ = "bbb"
) { say $r }

您也可以将:i放在正则表达式中

/:i < aaa bbb ccc >/

where子句执行智能匹配,就像~~进行智能匹配一样。因此像您一样使用两者都是多余的。

在基于智能匹配的功能中,使用$_运行的表达式被设置为要匹配的值。然后将该表达式的结果与输入进行匹配。

我将使用subset来尝试更好地解释它

subset Foo of Str where * ~~ m:i/< aaa bbb ccc >/;

当您与之匹配时,首先发生的是Str检查。
(这相当有效,类型专门化程序也许可以消除此检查)

'ccc' ~~ Str; # Str.ACCEPTS('ccc');

然后,where子句中的表达式就会在$_中被检查的值运行。

my $result = do given 'ccc' { * ~~ m:i/< aaa bbb ccc >/ }
# $result holds a closure

接下来发生的是,结果将与要测试的值进行智能匹配。

'ccc' ~~ $result; # $result.ACCEPTS('ccc');

在这种情况下,最后一个将取决于当时$_中发生的任何事情。
由于这将在语言的深处发生,因此您可能无法控制$_

对于where子句,它可以是任何东西。

$_ = 'fubar';

#                v--v
subset Foo where * ~~ m:i/
    { say '$_   = ', $_ }
    { say 'orig = ', $/.orig } # the string that is matched against
    < aaa bbb ccc >
/;

my $result = 'ccc' ~~ Foo;
# $_   = fubar
# orig = fubar

say $result;
# False

由于'fubar'/< aaa bbb ccc >/不匹配,结果为False

通过添加* ~~,您还添加了距离怪异的动作。

它不需要* ~~,因为Regex.ACCEPTS()不依赖$_

$_ = 'fubar';

subset Foo where m:i/
    { say '$_   = ', $_ }
    { say 'orig = ', $/.orig }
    < aaa bbb ccc >
/;

my $result = 'ccc' ~~ Foo;
# $_   = fubar
# orig = ccc

say $result
# True

Perl 6之所以执行以下两个级别的代码执行代码是有原因的

subset Bar where $_ eq any < aaa bbb ccc >;

my $result = do given 'ccc' { $_ eq any < aaa bbb ccc > }
# $result = True;

# 'ccc' ~~ $result;
$result.ACCEPTS('ccc');
# $result is True, and True.ACCEPTS() always returns True

请注意,可以将其缩短为:

subset Bar where any < aaa bbb ccc >;

my $result = do given 'ccc' { any < aaa bbb ccc > }
# $result = any < aaa bbb ccc >;

# 'ccc' ~~ $result;
$result.ACCEPTS('ccc');
# any(< aaa bbb ccc >).ACCEPTS('ccc')

所有智能匹配功能都会执行这种双重代码执行。

  • ~~

    'ccc' ~~ $_ eq any < aaa bbb ccc > # True.ACCEPTS('ccc')
    'ccc' ~~ any < aaa bbb ccc >       # any(…).ACCEPTS('ccc')
    
  • where

    subset Baz where $_ eq any < aaa bbb ccc >
    subset Baz where any < aaa bbb ccc >
    
  • when

    when $_ eq any < aaa bbb ccc > {…}
    when any < aaa bbb ccc > {…}
    

基本上,这是为了使您可以与值,表达式或代码进行智能匹配。
(代码实际上是Perl 6中的一种值)

10 ~~ 0..10;                # match against a value
10 ~~ Range.new(0,10);      # same as previous line

10 ~~ 0 ≤ * ≤ 10;           # match against code
10 ~~ -> $_ { 0 ≤ $_ ≤ 10 } # basically the same as previous line

10 ~~ 0 ≤ $_ ≤ 10;          # match against an expression with $_
                            # (not the same a previous two lines)

我想指出的是Perl 6中的正则表达式是一种函数。

my &foo = sub ($_) {$_ eq 'abc'};

my &bar = * eq 'abc';

my &baz = /^ abc $/;

my &zzz = 'abc' # ERROR

因此* ~~ /…/正在从已经是函数的事物中创建函数。
它将双重代码执行变成了双重代码执行。

m/…/中,m有效地使正则表达式/函数针对$_中发生的任何事情运行。

# $_ = Any; # initial value in $_

my &code = * ~~ m/abc/;
my &code = * ~~ ($_ ~~ /abc/); # same as previous line

还有rx,它与m相似,只不过它总是返回正则表达式本身而不是调用它的结果。 (光秃的/…/就像rx/…/一样)


刚开始时,智能匹配会令人困惑。
我认为这会使Perl 6的专家感到困惑。
(这仍然让我感到困惑,我知道它是如何工作的。)
我在这里尝试解释它的工作也很糟糕,但是我试图与您的问题相关,并且您使用~~使得解释起来更加困难。

为使自己保持理智,我尝试遵循一些基本规则。
这些适用于~~wherewhen

  • 使用文字或可能的文字。

    … ~~ 42
    … ~~ 'a'
    … ~~ any < aaa bbb ccc >
    … ~~ 1..10              # not actually a literal, but literal-like
    
  • 如果您使用的是表达式,请确保其只能返回TrueFalse
    与之匹配的值在$_中,这对where的{​​{1}}子句很有帮助。

    subset

    如果我刚刚使用过… ~~ 0 < $_ … ~~ $_.lc.contains('abc'); # Returns True or False when $_.lc.contains('abc') {…} … where $_.lc.contains('abc'); … ~~ $_.chars.Bool … ~~ ?$_.chars # prefix:« ? » coerces to Bool … ~~ ?~$_ # coerce to Str, coerce to Bool # True if the Str isn't empty # (so has the same effect as previous two examples) ,则只有在数值与长度相同的情况下它才会匹配。

    $_.chars

    这就是为什么我建议确保它返回布尔值的原因。

    此规则有一个例外。即调用一个例程,该例程返回您要智能匹配的值。

    '1'   ~~ $_.chars; # True
    '3.0' ~~ $_.chars; # True
    
    '1.0' ~~ $_.chars; # False (1.0 == 3)
    
    # that previous one is the same as
    do given '1.0' { $_.chars }.ACCEPTS( '1.0' ) # False
    # 3.ACCEPTS('1.0')
    

    (这是一个不好的例子,但说明了我的意思。)

  • 使用可通话对象。
    这有效地删除了代码执行的第一(表达)层。
    (结果值与函数的结果无关。)

    … ~~ Date.today.day-of-week;
    
  • 在其他两个智能匹配功能中都不要使用… ~~ *.lc.contains('abc') … ~~ {.lc.contains('abc')} … ~~ /:i abc/ # remember that a regex is a function when {.lc.contains('abc')} {…} … where {.lc.contains('abc')}; sub foo ( $_ ) { .lc.contains('abc') } … ~~ &foo when &foo {…} … where &foo;

    ~~

    如果有很长的表达,我会对此宽容一些,这只是其中的一部分。

    when     * ~~ /…/ {…} # don't do this
    … where  * ~~ /…/     # don't do this either
    
    … where $_ ~~ /…/     # No, … just no.
    

    我从来没有碰到过任何真正有用的代码。

    每次我看到when (.chars = 3 ?? $_ ~~ Str !! $_ ~~ Int) {…} 用于智能匹配时,如果没有它,效果会更好。

通过遵守上述规则~~仍然可以使用,但是出于不同的原因。

m:i/…/
Match实例上的

'ccc' ~~ m:i/ < aaa bbb ccc > /; my $result = do given 'ccc' { m:i/ < aaa bbb ccc > / } say $result.perl; # Match.new(pos => 3, orig => "ccc", hash => Map.new(()), from => 0, list => (), made => Any) $result = $result.ACCEPTS('ccc'); say $result.perl; # Match.new(pos => 3, orig => "ccc", hash => Map.new(()), from => 0, list => (), made => Any) 始终返回自身。它也总是真实的。

如果匹配失败,它仍然可以正常工作。 (它返回的是虚假的东西。)


再次遇到.ACCEPTS()约束和where条件与when的右侧相同。

答案 1 :(得分:4)

尝试一下:

sub MAIN(
   Str :$r where * ~~ / 'aaa' | 'bbb' | 'ccc' / = "bbb",
) { say $r }
正则表达式中的

< aaa bbb ccc >未作为数组插入,应按以下方式使用:

my @a = < aaa bbb ccc >;
say so "aaa" ~~ /@a/;