Perl函数的第二个参数采用BLOCK形式?

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

Perl function that takes a BLOCK as the second parameter?

问题

我想编写一个函数,其第一个参数是描述,第二个参数是代码块。我希望最终的代码看起来像这样:

verify "description" { boolean-assertion-block };

我特别想避免使用 sub 关键字。

如果我将描述放在代码块之后,没有问题:

sub verify (&$) { ... }

但是当我反转原型符号的顺序时:

sub verify ($&) { ... }

然后我会得到一个错误消息:

Type of arg 2 to main::verify must be sub {} (not anonymous hash ({})) at ...

显然,Perl对第一个参数是代码块时有特殊处理。

所以,也许我可以将它变成柯里化函数?

sub verify ($) {
    my $message = shift;
    return sub (&) { . . . }
}

但是然后我会在描述和代码块之间得到语法错误:

syntax error at ... near "" { "

我尝试更改调用语法以帮助编译器:

test "...", { BLOCK };
test("..."){ BLOCK };
test("...")({ BLOCK });
( test "...")({ BLOCK });

但是都不起作用。Perl能否实现我想要的功能?

英文:

I want to write a function whose first parameter is a description, and the second parameter is a code block. I want the finished code to read like:

verify "description" { boolean-assertion-block };

I'm specifically looking to avoid the sub keyword.

I can put the description AFTER the code block, no problem:

sub verify (&$) { ... }

But when I reverse the prototype symbol order:

sub verify ($&) { ... }

Then I get an error message:

Type of arg 2 to main::verify must be sub {} (not anonymous hash ({})) at ...

Clearly, Perl has special handling for the first argument being a code block.

So, maybe I can make it a curried function?

sub verify ($) {
    my $message = shift;
    return sub (&) { . . . }
}

But then I get a syntax error between the description and the code block:

syntax error at ... near ""..." { "

I tried altering the calling syntax to try to help out the compiler:

test "...", { BLOCK };
test("..."){ BLOCK };
test("...")({ BLOCK });
( test "..." )({ BLOCK });

No joy. Can Perl even do what I want to do?

答案1

得分: 5

(&) 原型仅在子程序的第一个参数中使用时才具有这种美感。来自 `perldoc perlsub`:

> 有趣的是,"&" 的一件事是,您可以使用它生成新的语法,前提是它在初始位置

提供类似美感水平的一种方法是:

```perl
sub verify ($%) {
  my ( $message, %opts ) = @_;
  my $coderef = $opts{using};
  ...;
}

sub using (&) {
  my ( $coderef ) = @_;
  return ( using => $coderef );
}

# `verify` 子程序接受一个名称,后跟一组选项哈希:
#
verify(
  "your message here",
  "using" => sub { ... },
);

# `using` 子程序返回一个满足该选项哈希的两元素列表:
#
verify "your message here", using {
  ...;
};

如果您迫切希望允许类似以下的语法:

verify "description" { boolean-assertion-block };

... 这仍然是可能的,但需要使用黑暗技巧。 Keyword::Simple 可能是您最好的选择,但还有 Devel::DeclareFilter::Simple 这些选项。


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

The `(&amp;)` prototype only has such niceness when used for the first argument in a sub. From `perldoc perlsub`:

&gt; The interesting thing about &quot;&amp;&quot; is that you can generate new syntax with it, provided it&#39;s in the initial position

One way to provide a similar level of niceness would be:

```perl
sub verify ($%) {
  my ( $message, %opts ) = @_;
  my $coderef = $opts{using};
  ...;
}

sub using (&amp;) {
  my ( $coderef ) = @_;
  return ( using =&gt; $coderef );
}

# The `verify` sub accepts a name followed by a hash of options:
#
verify(
  &quot;your message here&quot;,
  &quot;using&quot; =&gt; sub { ... },
);

# The `using` sub returns a two-element list that will satisfy
# that hash of options:
#
verify &quot;your message here&quot;, using {
  ...;
};

If you desperately want to allow a syntax exactly like:

verify &quot;description&quot; { boolean-assertion-block };

... then it is still possible, but requires the dark arts. Keyword::Simple is probably your best bet, but Devel::Declare and Filter::Simple are options.

答案2

得分: 4

只有当&amp;是原型中的第一件事情时,才能使用块语法。来自perlsub

> &amp;需要一个匿名子例程,如果作为第一个参数传递,就不需要sub关键字或后续的逗号。

其他自定义DSL,比如Dancer2Mojolicious,通常使用sub关键字。

get &#39;/foo&#39; =&gt; sub {
  ...
};

Plack::BuilderWeb::Scraper使用返回对象的块,然后可以嵌套使用。

英文:

You can only use the block syntax if the &amp; is the first thing in your prototype. From perlsub:

> An &amp; requires an anonymous subroutine, which, if passed as the first argument, does not require the sub keyword or a subsequent comma

Other custom DSL such as in Dancer2 or Mojolicious typically use the sub keyword.

get &#39;/foo&#39; =&gt; sub {
  ...
};

Plack::Builder and Web::Scraper use blocks that return objects, which then can be nested.

huangapple
  • 本文由 发表于 2023年2月6日 20:04:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/75361082.html
匿名

发表评论

匿名网友

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

确定