【问题标题】:Why does a Perl 6 Str do the Positional role, and how can I change []?为什么 Perl 6 Str 扮演 Positional 角色,如何更改 []?
【发布时间】:2017-12-30 17:43:57
【问题描述】:

我正在使用字符串的位置界面。我知道How can I slice a string like Python does in Perl 6?,但我很好奇我是否可以让这个东西只为傻笑而工作。

我想出了这个例子。阅读位置很好,但我不知道如何设置multi 来处理作业:

multi postcircumfix:<[ ]> ( Str:D $s, Int:D $n --> Str ) {
    $s.substr: $n, 1
    }
multi postcircumfix:<[ ]> ( Str:D $s, Range:D $r --> Str ) {
    $s.substr: $r.min, $r.max - $r.min + 1
    }
multi postcircumfix:<[ ]> ( Str:D $s, List:D $i --> List ) {
    map( { $s.substr: $_, 1 }, @$i ).list
    }

multi postcircumfix:<[ ]> ( Str:D $s, Int:D $n, *@a --> Str ) is rw {
    put "Calling rw version";
    }


my $string = 'The quick, purple butterfly';

{ # Works
my $single = $string[0];
say $single;
}

{ # Works
my $substring = $string[5..9];
say $substring;
}

{ # Works
my $substring = $string[1,3,5,7];
say $substring;
}

{ # NOPE!
$string[2] = 'Perl';
say $string;
}

最后一个不行:

T
uick,
(h   u c)
Index out of range. Is: 2, should be in 0..0
  in block <unit> at substring.p6 line 36

Actually thrown at:
  in block <unit> at substring.p6 line 36

不过,我不认为它会起作用。我不知道它应该有什么签名或特征来做我想做的事。

为什么[] 运算符在Str 上工作?

$ perl6
> "some string"[0]
some string

文档主要暗示[] 适用于具有Positional 角色的事物,并且这些事物在列表中。来自[] docs in operators

用于对@container 的零个或多个元素进行位置访问的通用接口,也称为“数组索引运算符”。

Str 令人惊讶地扮演了必要的角色,即使它不是@container(据我所知):

> "some string".does( 'Positional' )
True

有没有办法测试某个东西是@container

有没有办法让某个东西列出它的所有角色?

现在,知道一个字符串可以响应[],我如何才能确定哪个签名会匹配呢?我想知道正确的签名用于定义我自己的版本以通过[] 写入此字符串。

【问题讨论】:

  • 但是,例如,Int 不会发生同样的事情。它不做位置。
  • 您误用了.does - 它需要一个类型对象(或者,查看implementation,一个将与之比较的任意对象)而不是名称:"some string".does( 'Positional' ) 是相当于"some string".does( Str ),而不是"some string".does( Positional )
  • 那么.does 应该抱怨一下。

标签: role raku multimethod


【解决方案1】:

实现这一点的一种方法是扩充Str 类,因为您实际上只需要重写AT-POS 方法(Str 通常继承自Any):

use MONKEY;
augment class Str {
    method AT-POS($a) {
        self.substr($a,1);
    }
}
say "abcde"[3];     # d
say "abcde"[^3];    # (a b c)

更多信息可以在这里找到:https://docs.raku.org/language/subscripts#Methods_to_implement_for_positional_subscripting

【讨论】:

    【解决方案2】:

    有一个模块可以让你这样做:

    https://github.com/zoffixznet/perl6-Pythonic-Str

    但是:

    此模块不提供 Str.AT-POS 或使 Str 类型执行 Positional 或 Iterable 角色。由于 Str 类型不扮演这些角色的固有假设,后者会导致核心和非核心代码的各种后果。这在简单的英语中意味着您只能使用 [...] postcircumfix 运算符来索引您的字符串,并且不能随意将它们视为字符列表 - 如果需要,只需调用 .comb 即可。`

    【讨论】:

      【解决方案3】:

      要使您的rw 版本正常工作,您首先需要使可能发生突变的 Str 也可能发生突变rw,并且它需要返回一些东西,这反过来也是rw。对于字符串的特定情况,您可以简单地这样做:

      multi postcircumfix:<[ ]> ( Str:D $s is rw, Int:D $i --> Str ) is rw {
         return $s.substr-rw: $i, 1;
      }
      

      很多时候,您会希望 rw 子例程返回 Proxy 的实例:

      multi postcircumfix:<[ ]> ( Str:D $s is rw, Int:D $i --> Str ) is rw {
         Proxy.new: FETCH => sub { $s.substr: $i },
             STORE => sub -> $newval { $s.substr-rw( $i, 1 ) = $newval }
      }
      

      虽然我还没有看到使用它的生产代码,但还有一个 return-rw 运算符,你偶尔会需要它而不是 return

      sub identity( $x is rw ) is rw { return-rw $x }
      identity( my $y ) = 42; # Works, $y is 42.
      
      sub identity-fail( $x is rw ) is rw { return $x }
      identity-fail( my $z ) = 42; # Fails: "Cannot assign to a readonly variable or a value"
      

      如果一个函数在没有执行returnreturn-rw 或抛出异常的情况下到达末尾,则返回最后一条语句的值,并且(目前)它的行为就像它在return-rw 之前一样。

      sub identity2( $x is rw ) is rw { $x }
      identity2( my $w ) = 42; # Works, $w is 42.
      

      【讨论】:

        猜你喜欢
        • 2020-01-25
        • 1970-01-01
        • 2020-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-18
        • 2023-03-20
        相关资源
        最近更新 更多