传递函数参数的Perl自定义语法
我使用perl已经有一段时间了。 我想知道如何在perl中运行以下操作:传递函数参数的Perl自定义语法,perl,parsing,lexical,Perl,Parsing,Lexical,我使用perl已经有一段时间了。 我想知道如何在perl中运行以下操作: subtract(40)(20) 要获得结果,请执行以下操作: 20 我想我必须看看Perl的自定义解析技术。 这就是我现在看到的: 及 现在,我不知道该找什么或做什么。 任何关于如何进行这方面的帮助,阅读内容将不胜感激。请讲清楚。 谢谢。如果你能忍受一个符号和一个箭头的增加,你可以减去 my $subtract = sub { my($x) = @_; sub { my($y) = @_; $x -
subtract(40)(20)
要获得结果,请执行以下操作:
20
我想我必须看看Perl的自定义解析技术。
这就是我现在看到的:
及
现在,我不知道该找什么或做什么。
任何关于如何进行这方面的帮助,阅读内容将不胜感激。请讲清楚。
谢谢。如果你能忍受一个符号和一个箭头的增加,你可以
减去
my $subtract = sub {
my($x) = @_;
sub { my($y) = @_; $x - $y };
};
称之为
my $result = $subtract->(40)(20);
如果箭头可接受,但符号不可接受,则根据需要重铸subtract
sub subtract {
my($x) = @_;
sub { my($y) = @_; $x - $y };
};
本例中的调用如下所示
my $result = subtract(40)->(20);
如果你能忍受一个符号和一个箭头的增加,你可以像在
my $subtract = sub {
my($x) = @_;
sub { my($y) = @_; $x - $y };
};
称之为
my $result = $subtract->(40)(20);
如果箭头可接受,但符号不可接受,则根据需要重铸subtract
sub subtract {
my($x) = @_;
sub { my($y) = @_; $x - $y };
};
本例中的调用如下所示
my $result = subtract(40)->(20);
请不要为了解决问题而在程序上附加不正确的语法扩展。
您需要的是闭包,以及一种有时称为curry的技术
curry是将一个包含多个参数的函数转换为一个函数的工作,该函数使用一个参数多次调用。例如,考虑
sub subtract {
my ($x, $y) = @_;
return $x - $y;
}
现在我们可以创建一个已经提供第一个参数的子例程:
sub subtract1 { subtract(40, @_) }
调用subtract1(20)
现在计算为20
我们可以改为使用匿名子例程,这使它更加灵活:
my $subtract = sub { subtract(40, @_) };
$subtract->(20);
我们不需要这个变量:
sub { subtract(40, @_) }->(20); # equivalent to subtract(40, 20)
我们可以直接写减法
:
sub subtract_curried {
my $x = shift;
# don't return the result, but a subroutine that calculates the result
return sub {
my $y = shift;
return $x - $y;
};
}
现在:subtract\u curried(40)->(20)
–注意中间的箭头,因为我们正在处理代码引用(匿名子例程或闭包的另一个名称)
这种编写函数的风格在Haskell或OCaml等函数式语言中更为常见,因为它们的语法更为美观。它允许非常灵活的功能组合。如果您对Perl中的这种编程感兴趣,您可能需要阅读。请不要在程序上附加不正确的语法扩展来解决已解决的问题。
您需要的是闭包,以及一种有时称为curry的技术
curry是将一个包含多个参数的函数转换为一个函数的工作,该函数使用一个参数多次调用。例如,考虑
sub subtract {
my ($x, $y) = @_;
return $x - $y;
}
现在我们可以创建一个已经提供第一个参数的子例程:
sub subtract1 { subtract(40, @_) }
调用subtract1(20)
现在计算为20
我们可以改为使用匿名子例程,这使它更加灵活:
my $subtract = sub { subtract(40, @_) };
$subtract->(20);
我们不需要这个变量:
sub { subtract(40, @_) }->(20); # equivalent to subtract(40, 20)
我们可以直接写减法
:
sub subtract_curried {
my $x = shift;
# don't return the result, but a subroutine that calculates the result
return sub {
my $y = shift;
return $x - $y;
};
}
现在:subtract\u curried(40)->(20)
–注意中间的箭头,因为我们正在处理代码引用(匿名子例程或闭包的另一个名称)
这种编写函数的风格在Haskell或OCaml等函数式语言中更为常见,因为它们的语法更为美观。它允许非常灵活的功能组合。如果您对这种Perl编程感兴趣,可能需要阅读。我建议您尝试一下。Parse::Keyword对于解析自定义语法非常有用,因为它允许您回调Perl解析器的各个部分,例如Parse_listexpr
,Parse_block
,Parse_fullstmt
,等等(请参阅)
它有一个缺点,如果您使用这些函数来解析关闭变量的表达式,这些函数的处理会很糟糕,但这是可以解决的
Parse::关键字(包括PadWalker诡计)是什么用途;这就完成了一些相当复杂的事情!p5 mop redux的早期版本也使用了它
无论如何,这里有一个演示如何解析你的奇怪函数
use v5.14;
use strict;
use warnings;
# This is the package where we define the functions...
BEGIN {
package Math::Weird;
# Set up parsing for the functions
use Parse::Keyword {
add => \&_parser,
subtract => \&_parser,
multiply => \&_parser,
divide => \&_parser,
};
# This package is an exporter of course
use parent 'Exporter::Tiny';
our @EXPORT = qw( add subtract multiply divide );
# We'll need these things from PadWalker
use PadWalker qw( closed_over set_closed_over peek_my );
sub add {
my @numbers = _grab_args(@_);
my $sum = 0;
$sum += $_ for @numbers;
return $sum;
}
sub subtract {
my @numbers = _grab_args(@_);
my $diff = shift @numbers;
$diff -= $_ for @numbers;
return $diff;
}
sub multiply {
my @numbers = _grab_args(@_);
my $product = 1;
$product *= $_ for @numbers;
return $product;
}
sub divide {
my @numbers = _grab_args(@_);
my $quotient = shift @numbers;
$quotient /= $_ for @numbers;
return $quotient;
}
sub _parser {
lex_read_space;
my @args;
while (lex_peek eq '(')
{
# read "("
lex_read(1);
lex_read_space;
# read a term within the parentheses
push @args, parse_termexpr;
lex_read_space;
# read ")"
lex_peek eq ')' or die;
lex_read(1);
lex_read_space;
}
return sub { @args };
}
# In an ideal world _grab_args would be implemented like
# this:
#
# sub _grab_args { map scalar(&$_), @_ }
#
# But because of issues with Parse::Keyword, we need
# something slightly more complex...
#
sub _grab_args {
my $caller_vars = peek_my(2);
map {
my $code = $_;
my $closed_over = closed_over($code);
$closed_over->{$_} = $caller_vars->{$_} for keys %$closed_over;
set_closed_over($code, $closed_over);
scalar $code->();
} @_;
}
# We've defined a package inline. Mark it as loaded, so
# that we can `use` it below.
$INC{'Math/Weird.pm'} = __FILE__;
};
use Math::Weird qw( add subtract multiply );
say add(2)(3); # says 5
say subtract(40)(20); # says 20
say multiply( add(2)(3) )( subtract(40)(20) ); # says 100
我建议你试试。Parse::Keyword对于解析自定义语法非常有用,因为它允许您回调Perl解析器的各个部分,例如Parse_listexpr
,Parse_block
,Parse_fullstmt
,等等(请参阅)
它有一个缺点,如果您使用这些函数来解析关闭变量的表达式,这些函数的处理会很糟糕,但这是可以解决的
Parse::关键字(包括PadWalker诡计)是什么用途;这就完成了一些相当复杂的事情!p5 mop redux的早期版本也使用了它
无论如何,这里有一个演示如何解析你的奇怪函数
use v5.14;
use strict;
use warnings;
# This is the package where we define the functions...
BEGIN {
package Math::Weird;
# Set up parsing for the functions
use Parse::Keyword {
add => \&_parser,
subtract => \&_parser,
multiply => \&_parser,
divide => \&_parser,
};
# This package is an exporter of course
use parent 'Exporter::Tiny';
our @EXPORT = qw( add subtract multiply divide );
# We'll need these things from PadWalker
use PadWalker qw( closed_over set_closed_over peek_my );
sub add {
my @numbers = _grab_args(@_);
my $sum = 0;
$sum += $_ for @numbers;
return $sum;
}
sub subtract {
my @numbers = _grab_args(@_);
my $diff = shift @numbers;
$diff -= $_ for @numbers;
return $diff;
}
sub multiply {
my @numbers = _grab_args(@_);
my $product = 1;
$product *= $_ for @numbers;
return $product;
}
sub divide {
my @numbers = _grab_args(@_);
my $quotient = shift @numbers;
$quotient /= $_ for @numbers;
return $quotient;
}
sub _parser {
lex_read_space;
my @args;
while (lex_peek eq '(')
{
# read "("
lex_read(1);
lex_read_space;
# read a term within the parentheses
push @args, parse_termexpr;
lex_read_space;
# read ")"
lex_peek eq ')' or die;
lex_read(1);
lex_read_space;
}
return sub { @args };
}
# In an ideal world _grab_args would be implemented like
# this:
#
# sub _grab_args { map scalar(&$_), @_ }
#
# But because of issues with Parse::Keyword, we need
# something slightly more complex...
#
sub _grab_args {
my $caller_vars = peek_my(2);
map {
my $code = $_;
my $closed_over = closed_over($code);
$closed_over->{$_} = $caller_vars->{$_} for keys %$closed_over;
set_closed_over($code, $closed_over);
scalar $code->();
} @_;
}
# We've defined a package inline. Mark it as loaded, so
# that we can `use` it below.
$INC{'Math/Weird.pm'} = __FILE__;
};
use Math::Weird qw( add subtract multiply );
say add(2)(3); # says 5
say subtract(40)(20); # says 20
say multiply( add(2)(3) )( subtract(40)(20) ); # says 100
您可以创建:
并使用它:
#!/usr/bin/perl
use BracketFilter;
subtract(40)(20);
sub subtract {
return $_[0] - $_[1];
}
您可以创建:
并使用它:
#!/usr/bin/perl
use BracketFilter;
subtract(40)(20);
sub subtract {
return $_[0] - $_[1];
}
@心痛:请忘记这个挑战,因为它对解析器和用户都没有意义
您可以考虑使用fn[x][y]
或fn{x}{y}
,这是有效的语法变体,即您可以堆叠[]
和{}
,但不能堆叠列表,
或者fn(x,y)
或者fn(x)->(y)
这些看起来不错的语法变体也是有效且有意义的语法变体。
但是fn(x)(y)
将不知道第二个列表应该在哪个上下文中使用
对于fn(x)(y)
通常的解释是fn(x);(y) =>(y)
。它在评估第一次调用后返回第二个列表。@Heartache:请忘记这个挑战,因为它对解析器和用户都没有意义
您可以考虑使用fn[x][y]
或fn{x}{y}
,这是有效的语法变体,即您可以堆叠[]
和{}
,但不能堆叠列表,
或者fn(x,y)
或者fn(x)->(y)
这些看起来不错的语法变体也是有效且有意义的语法变体。
但是fn(x)(y)
将不知道第二个列表应该在哪个上下文中使用
对于fn(x)(y)
通常的解释是fn(x);(y) =>(y)
。它在评估第一次呼叫后返回第二个列表。您想做什么?那个lo