如何在Raku中的给定块内使用”when”来智能匹配一个值列表?

huangapple go评论66阅读模式
英文:

How do I smartmatch against a list of values with when inside a given block in Raku?

问题

Here's the translated content you requested:

我发现了这个JS代码片段:
```js
function append(demo = "", file = "") {
    const extra = "ctl=1&embed=1";
    if (demo && file)  return `/${demo}/?file=${file}&${extra}`;
    if (!demo && file) return `/?file=${file}&${extra}`;
    if (demo && !file) return `/${demo}&${extra}`;
    return `?${extra}`; 
}

我可以轻松地将这个代码移植到Raku,并使用if语句,但我认为使用given/when语句来展示这个特性会是一种不错的方式。我想出了以下代码:

sub append(Str :$demo, Str :$file) {
    my $extra = "ctl=1&embed=1";
    given ($demo, $file) {
        when $demo.so,  $file.so  { "/$demo/?file=$file&$extra" } 
        when $demo.not, $file.so  { "/?file=$file&$extra" } 
        when $demo.so,  $file.not { "/$demo?$extra" } 
        default                   { "?$extra" }
    }
}

say append :file("here"), :demo("there"); # /there/?file=here&ctl=1&embed=1
say append :file("here");                 # /?file=here&ctl=1&embed=1
say append :demo("here");                 # /here?ctl=1&embed=1
say append;                               # ?ctl=1&embed=1

然而,这段代码相当重复,而且我甚至不确定它是否符合Raku的习惯用法,所以我想我可以这样做:

sub append(Str :$demo = '', Str :$file = '') {
    my $extra = "ctl=1&embed=1";
    given ($demo.so, $file.so) {
        when (True,  True)  { "/$demo/?file=$file&$extra" } 
        when (False, True)  { "/?file=$file&$extra" } 
        when (True,  False) { "/$demo?$extra" } 
        default             { "?$extra" }
    }
}

然而,这并不能按预期工作。因此,是否有可能将一系列值绑定到主题变量$_,然后使用when语句进行智能匹配?我(误)记得Daniel“codesections”Sockwell曾经做过类似的事情,但我记不清在哪里看到的了。


Please note that I've retained the HTML entity references (e.g., `"`) in the translated content as they were in the original text. If you have any specific questions or requests related to this code or translation, feel free to ask.

<details>
<summary>英文:</summary>

I came across this JS code snippet:
```js
function append(demo = &quot;&quot;, file = &quot;&quot;) {
    const extra = &quot;ctl=1&amp;embed=1&quot;;
    if (demo &amp;&amp; file)  return `/${demo}/?file=${file}&amp;${extra}`;
    if (!demo &amp;&amp; file) return `/?file=${file}&amp;${extra}`;
    if (demo &amp;&amp; !file) return `/${demo}&amp;${extra}`;
    return `?${extra}`; 
}

I can port this easily to Raku using ifs but I thought using given/when would be a nice way of showcasing that feature. I came up with the following:

sub append(Str :$demo, Str :$file) {
    my $extra = &quot;ctl=1&amp;embed=1&quot;;
    given ($demo, $file) {
        when $demo.so,  $file.so  { &quot;/$demo/?file=$file&amp;$extra&quot; } 
        when $demo.not, $file.so  { &quot;/?file=$file&amp;$extra&quot; } 
        when $demo.so,  $file.not { &quot;/$demo?$extra&quot; } 
        default                   { &quot;?$extra&quot; }
    }
}

say append :file(&quot;here&quot;), :demo(&quot;there&quot;); # /there/?file=here&amp;ctl=1&amp;embed=1
say append :file(&quot;here&quot;);                 # /?file=here&amp;ctl=1&amp;embed=1
say append :demo(&quot;here&quot;);                 # /here?ctl=1&amp;embed=1
say append;                               # ?ctl=1&amp;embed=1

However it's quite repetitive and I'm not even sure if it's idiomatic Raku so I figured I could do the following:

sub append(Str :$demo = &#39;&#39;, Str :$file = &#39;&#39;) {
    my $extra = &quot;ctl=1&amp;embed=1&quot;;
    given ($demo.so, $file.so) {
        when (True,  True)  { &quot;/$demo/?file=$file&amp;$extra&quot; } 
        when (False, True)  { &quot;/?file=$file&amp;$extra&quot; } 
        when (True,  False) { &quot;/$demo?$extra&quot; } 
        default             { &quot;?$extra&quot; }
    }
}

This doesn't work as expected though. Thus, is it even possible to bind a list of values to the topic variable $_ and smartmatch against it with whens? I (mis)remember Daniel "codesections" Sockwell doing something to this extent but I cannot remember where.

答案1

得分: 4

我运行了你的代码并得到了这个错误:

在字符串上下文中使用了未初始化的 Str 类型值
可以使用 .^name.raku.gist 或 .say 方法将其转换为有意义的内容

你可以在 append() 签名中添加默认值来初始化参数值,就像这样:

sub append(Str :$demo='', Str :$file='') {

而且不需要使用 do given,普通的 given 就可以。

英文:

I ran your code and got this error:

Use of uninitialized value of type Str in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.

You can just add default values in the append() signature like this to initialize the argument values:

sub append(Str :$demo=&#39;&#39;, Str :$file=&#39;&#39;) {

Oh and no need for do given, just plain given is fine.

答案2

得分: 2

> 我提出了以下

这是巧合的。您对True使用smartmatch

在这种情况下,您不需要给出:

sub append(Str :$demo, Str :$file, :$extra = &quot;ctl=1&amp;embed=1&quot;) {
    when $demo.so  &amp;  $file.so  { &quot;/$demo/?file=$file&amp;$extra&quot; }
    when              $file.so  { &quot;/?file=$file&amp;$extra&quot; }
    when $demo.so               { &quot;/$demo?$extra&quot; }
    default                     { &quot;?$extra&quot; }
}

> 我可以将值列表绑定到主题变量$_并使用whens进行智能匹配吗?

可以的:

sub append(Str :$demo, Str :$file, :$extra = &quot;ctl=1&amp;embed=1&quot;) {
    given ($demo, $file) {
        when :so , :so  { &quot;/$demo/?file=$file&amp;$extra&quot; }
        when :!so, :so  { &quot;/?file=$file&amp;$extra&quot; }
        when :so , :!so { &quot;/$demo?$extra&quot; }
        default         { &quot;?$extra&quot; }
    }
}

您可以对Signature使用smartmatch:

sub append(|c (Str :$demo, Str :$file)) {
    my $extra = &quot;ctl=1&amp;embed=1&quot;;
    given c {
        when :(:demo($)!, :file($)!)  { &quot;/$demo/?file=$file&amp;$extra&quot; }
        when :(:file($)!)             { &quot;/?file=$file&amp;$extra&quot; }
        when :(:demo($)!)             { &quot;/$demo?$extra&quot; }
        default                       { &quot;?$extra&quot; }
    }
}

但使用multi-dispatch更有趣:

constant $extra = &#39;ctl=1&amp;embed=1&#39;;
proto append (Str :$demo,Str :$file) {*}
multi append (:$demo!, :$file!) { &quot;/$demo/?file=$file&amp;$extra&quot; }
multi append (:$file!)          { &quot;/?file=$file&amp;$extra&quot; }
multi append (:$demo!)          { &quot;/$demo?$extra&quot; }
multi append ()                 { &quot;?$extra&quot; }
英文:

> I came up with the following

This works by a coincidence. You use smartmatch against True

You do not need given in this case:

sub append(Str :$demo, Str :$file, :$extra = &quot;ctl=1&amp;embed=1&quot;) {
    when $demo.so  &amp;  $file.so  { &quot;/$demo/?file=$file&amp;$extra&quot; }
    when              $file.so  { &quot;/?file=$file&amp;$extra&quot; }
    when $demo.so               { &quot;/$demo?$extra&quot; }
    default                     { &quot;?$extra&quot; }
}

> can I bind a list of values to the topic variable $_ and smartmatch against it with whens?

Yes, you can:

sub append(Str :$demo, Str :$file, :$extra = &quot;ctl=1&amp;embed=1&quot;) {
    given ($demo, $file) {
        when :so , :so  { &quot;/$demo/?file=$file&amp;$extra&quot; }
        when :!so, :so  { &quot;/?file=$file&amp;$extra&quot; }
        when :so , :!so { &quot;/$demo?$extra&quot; }
        default         { &quot;?$extra&quot; }
    }
}

You can use smartmatch against Signature:

sub append(|c (Str :$demo, Str :$file)) {
    my $extra = &quot;ctl=1&amp;embed=1&quot;;
    given c {
        when :(:demo($)!, :file($)!)  { &quot;/$demo/?file=$file&amp;$extra&quot; }
        when :(:file($)!)             { &quot;/?file=$file&amp;$extra&quot; }
        when :(:demo($)!)             { &quot;/$demo?$extra&quot; }
        default                       { &quot;?$extra&quot; }
    }
}

but it is more fun to use multi-dispatch

constant $extra = &#39;ctl=1&amp;embed=1&#39;;
proto append (Str :$demo,Str :$file) {*}
multi append (:$demo!, :$file!) { &quot;/$demo/?file=$file&amp;$extra&quot; }
multi append (:$file!)          { &quot;/?file=$file&amp;$extra&quot; }
multi append (:$demo!)          { &quot;/$demo?$extra&quot; }
multi append ()                 { &quot;?$extra&quot; }

huangapple
  • 本文由 发表于 2023年5月15日 00:36:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76248589.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定