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

Nor*_*ood 8 perl6

我想MAIN()用字符串匹配来限制参数.这有效:

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

$ perl6 tb.p6 -r="ccc"
ccc
Run Code Online (Sandbox Code Playgroud)

但这不是:

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 { ... }>] 
Run Code Online (Sandbox Code Playgroud)

Bra*_*ert 7

最大的问题是你用两个*来制作WhateverCode lambda和m.

m/…/与发生的任何事情相匹配$_.
这有效地发生在外面~~.

如果你只使用m/…/它会有效

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

你也可以放在:i正则表达式的内部

/:i < aaa bbb ccc >/
Run Code Online (Sandbox Code Playgroud)

一个where子句做智能匹配,就像~~智能匹配一样.所以像你一样使用两者都是多余的.

在基于smartmatch的功能中,表达式运行时$_将设置为匹配的值.然后将该表达式的结果与输入匹配.

我打算用a subset试着帮助解释一下

subset Foo of Str where * ~~ m:i/< aaa bbb ccc >/;
Run Code Online (Sandbox Code Playgroud)

当你匹配它时,首先发生的是Str检查.
(这是相当高效的,类型专业化器可能能够消除这种检查)

'ccc' ~~ Str; # Str.ACCEPTS('ccc');
Run Code Online (Sandbox Code Playgroud)

然后,子句中的表达式将where检入值的情况下运行$_.

my $result = do given 'ccc' { * ~~ m:i/< aaa bbb ccc >/ }
# $result holds a closure
Run Code Online (Sandbox Code Playgroud)

接下来发生的是结果与正在测试的值进行智能匹配.

'ccc' ~~ $result; # $result.ACCEPTS('ccc');
Run Code Online (Sandbox Code Playgroud)

在这种情况下,最后一个将取决于$_当时发生的事情.
由于现在会发生在语言深处,您可能无法控制$_.

在一个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
Run Code Online (Sandbox Code Playgroud)

因为'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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

请注意,它可以缩短为:

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')
Run Code Online (Sandbox Code Playgroud)

所有智能匹配功能都会执行此双重代码执行.

基本上这是为了使您可以针对值或针对表达式或针对代码进行智能匹配.
(代码实际上是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)
Run Code Online (Sandbox Code Playgroud)

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

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

my &bar = * eq 'abc';

my &baz = /^ abc $/;

my &zzz = 'abc' # ERROR
Run Code Online (Sandbox Code Playgroud)

所以* ~~ /…/从已经是函数的东西创建函数.
它还将双代码执行转变为四重代码执行.

m/…/m有效地使正则表达式/函数对无论发生什么事要在运行$_.

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

my &code = * ~~ m/abc/;
my &code = * ~~ ($_ ~~ /abc/); # same as previous line
Run Code Online (Sandbox Code Playgroud)

还有rx,类似于m它除了它总是返回正则表达式本身而不是调用它的结果.(裸露的/…/行为rx/…/)


首次启动时,智能匹配可能会令人困惑.
我认为对于那些在Perl 6中是专家的人来说可能会让人感到困惑.
(这对我来说仍然有点混乱,我知道它是如何工作的.)
我也做了一个很差的工作,试图在这里解释它,但我是试图与你的问题相关,你的使用~~使其更难解释.

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

  • 如果可能,请使用文字或文字.

    … ~~ 42
    … ~~ 'a'
    … ~~ any < aaa bbb ccc >
    … ~~ 1..10              # not actually a literal, but literal-like
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果您正在使用表达式,请确保它只能返回TrueFalse.
    匹配的值$_可以在a的where子句中有用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)
    
    Run Code Online (Sandbox Code Playgroud)

    如果我刚刚使用$_.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')
    
    Run Code Online (Sandbox Code Playgroud)

    这就是为什么我建议确保它返回Bool.

    这条规则有一个例外.即调用一个返回您想要智能匹配的值的例程.

    … ~~ Date.today.day-of-week;
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 使用Callable.
    这有效地删除了代码执行的第一个(表达式)层.
    (结果值是函数的结果.)

    … ~~ *.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;
    
    Run Code Online (Sandbox Code Playgroud)
  • 不要~~在其他两个智能匹配功能中使用.

    when     * ~~ /…/ {…} # don't do this
    … where  * ~~ /…/     # don't do this either
    
    … where $_ ~~ /…/     # No, … just no.
    
    Run Code Online (Sandbox Code Playgroud)

    如果有一个长表达式,我会对这个稍微宽一点,这只是它的一部分.

    when (.chars = 3 ?? $_ ~~ Str !! $_ ~~ Int) {…}
    
    Run Code Online (Sandbox Code Playgroud)

    我从来没有遇到任何真正有用的代码.

    每次我~~在智能匹配中看到过,如果没有它,它会更好.

坚持上述规则m:i/…/仍然有效,但原因不同.

'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)
Run Code Online (Sandbox Code Playgroud)

.ACCEPTS()在Match的实例上总是返回自己.它也总是真实的.

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


同样,where约束和when条件与右侧相同~~.