我试图模仿reduce
中的List::Util
函数。
我遇到的问题是子例程引用已传递给我的reducer
无法访问词汇$a
和$b
变量。
我试过宣布他们
在reduce
子程序中包含my
和local
,但都没有效果。
我当前的子程序是这样的,用于测试our $DEBUG = 1;
在文件的顶部:
sub reduce(&@) {
my $code = shift;
if ( @_ == 0 ) {
print "No items passed to reduce, returning undef\n" if $DEBUG;
return undef;
}
if ( @_ == 1 ) {
print "One item passed to reduce, returning it\n" if $DEBUG;
return shift;
}
my $a = shift; # Also tried "local $a = shift;"
my $b = shift; # Also tried "local $b = shift;"
print "Starting reduction loop with a = [$a] and b = [$b]\n" if $DEBUG;
while ( @_ ) {
$a = $code->();
$b = shift;
print "- Reductive iteration ended with a = [$a] and b = [$b]\n" if $DEBUG;
}
my $val = &{$code};
print "- Finished reductive loop with value [$val]\n" if $DEBUG;
return $val;
}
我称之为
print "" . (reduce { print "-- $a + $b\n"; $a + $b; } 1..10) . "\n";
我的输出是:
Starting reduction loop with a = [0] and b = [1]
-- +
- Reductive iteration ended with a = [0] and b = [2]
-- +
- Reductive iteration ended with a = [0] and b = [3]
-- +
- Reductive iteration ended with a = [0] and b = [4]
-- +
- Reductive iteration ended with a = [0] and b = [5]
-- +
- Reductive iteration ended with a = [0] and b = [6]
-- +
- Reductive iteration ended with a = [0] and b = [7]
-- +
- Reductive iteration ended with a = [0] and b = [8]
-- +
- Reductive iteration ended with a = [0] and b = [9]
-- +
- Reductive iteration ended with a = [0] and b = [10]
-- +
- Finished reductive loop with value [0]
0
如何将子例程引用传递给reduce
以查看$a
和$b
?
答案 0 :(得分:2)
看看another pure perl reduce implementation。关键的见解是,传递给$a
的子中的$b
和reduce
是调用包命名空间中的全局变量,而在reduce
实现中,您执行了一个小符号表巫术来获得它们。我在这里更改了词法变量名称(到$aa
和$bb
),以区别于调用者中的$a
和$b
:
sub reduce (&@) {
my $f = shift;
...
my $pkg = caller;
my $aa = shift; # first element in list (after function spec)
no strict 'refs';
# makes '$a' in calling package an alias for local '$aa'
local *{"${pkg}::a"} = \$aa;
# $glob_b is a reference to stash for `b` in calling package
my $glob_b = \*{"${pkg}::b"};
foreach my $bb (@_) {
# $glob_b is reference to stash for caller's 'b'
# *$glob_b is the stash for caller's 'b'
# assigning scalar reference to *$glob_b updates '$b' in calling pkg
local *$glob_b = \$bb;
# $aa is aliased to caller's $a, so $a is updated within this loop
$aa = $f->();
}
$aa;
}
答案 1 :(得分:1)
最好不要猜测如何传递值。如果您在阅读文档后真的不知道该怎么做,那么弄乱my
和local
会让您更加困惑。这两个想法都将确保在当前代码块结束时丢弃这些变量,但由于local
与包变量一起使用,对传递的子例程引用的任何调用都将是能够看到那些临时值
你没有定义调用reduce
的真正目的,所以我写了一些东西,它只是连接列表中的所有值并返回结果。请始终提供我们可以测试和修复的内容
这是一个有效的my_reduce
。请注意,真实reduce
必须检查调用代码的命名空间,并修改 包中的$a
和$b
。在这里,我只是将my_reduce
放在与调用代码相同的包中
我还并行使用List::Util::reduce
以确保两个结果一致
use strict;
use warnings 'all';
use feature 'say';
use List::Util ();
my $DEBUG = 1;
sub my_reduce(&@);
my @abc = 'a' .. 'z';
say List::Util::reduce(
sub { $a . $b },
@abc
);
say my_reduce(
sub { $a . $b },
@abc
);
sub my_reduce(&@) {
my $code = shift;
if ( @_ == 0 ) {
print "No items passed to reduce, returning undef\n" if $DEBUG;
return undef;
}
elsif ( @_ == 1 ) {
print "One item passed to reduce, returning it.\n" if $DEBUG;
return shift;
}
else {
while ( @_ > 1 ) {
local ($a, $b) = splice @_, 0, 2;
unshift @_, $code->();
}
return shift;
}
}
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz