Chinaunix
标题:
Perl 语言缺失的语言特性
[打印本页]
作者:
104359176
时间:
2013-08-21 15:12
标题:
Perl 语言缺失的语言特性
在用 Perl 编程的过程中,实际中遇到一个问题,就是遍历一个数组的数组,针对这些每条数据执行一些规则。然后把改变后的数据保存回去。
我于是做了一个深度优先的迭代器,然后写了一个获取元素位置的算法。每次获取一个位置,然后根据这个位置保存回去。
感觉这种情况让代码的复杂度增加了一层。
后来发现 Ruby 的迭代器加代码块是解决这个问题的好办法,Python 的生成器也是类似的东西。
当然 Lisp 有很多机制可以实现简化这种编程模式。
但我在 Perl 中找不到这种简化的好办法。难道是 Perl 中缺失了这个特性吗?
我原来以为设计一个传递函数的函数能解决这个办法。但定义的函数本身不能在 调用的上下文中 获取所有局部变量。
大家认为呢?
作者:
zhlong8
时间:
2013-08-21 15:45
@AoA = (
[1..10],
[11 .. 20],
);
for my $ary (@AoA) {
for (@$ary) {
$_ *= 2;
}
}
矩阵每个元素 x2
是这样吗?
作者:
yakczh_cu
时间:
2013-08-21 15:59
本帖最后由 yakczh_cu 于 2013-08-21 16:02 编辑
sub passfunc($){
my $para=shift;
my $code=shift;
my @out=$code->($para);
}
$handle = sub {
my $para=shift;
@out=map { s/http/ftp/g; $_} @$para;
};
@data=('http://www.baidu.com','http://www.google');
@out=passfunc(\@data,$handle);
print join("\n",@out);
复制代码
要什么变量传进去就行了,只需要准备数据和处理单元,不用改变程序主流程
作者:
104359176
时间:
2013-08-21 16:12
本帖最后由 104359176 于 2013-08-21 16:21 编辑
回复
2#
zhlong8
是这样的,但实际的数据结构是一个数组的数组,每个数组可能是一个单独的数组,也可能是数组的数组,还可能是数组的数组的数组。要实现一个统一的接口,能迭代这个复杂结构中的每个独立的数组,并且能保存回去。
@array = (
[1, 2, 3],
[ [4,5,6], [7,8,9],
[ [ [ 1,2,3],[4,5,6] ], [ [7,8,9], [1,2,3]]],
);
我针对三种结构做了一个统一的迭代器 get_array();
但只能用 while 来遍历,每次处理完,用一个 set_array() 来保存数据。
get_array() 和 set_array() 必须成对使用。
如果数据结构在发生变化,迭代器的设计就非常复杂了。
有没有一个通用的模式能处理这个问题呢?
因为这个更新结构的过程,要抽象成一个函数,传递到其他的函数中。而且要留几个参数,来控制这个过程的一些行为。
作者:
104359176
时间:
2013-08-21 16:15
回复
3#
yakczh_cu
需要在一个通用控制结构中调用这个函数,要求这个函数能继承所有可见上下文的变量,靠传递变量的方式不靠谱。
作者:
zhlong8
时间:
2013-08-21 16:32
回复
4#
104359176
use strict;
use warnings;
sub forall {
my($sub, $sth) = @_;
for my $v (@$sth) {
if (ref $v eq 'ARRAY') {
forall($sub, $v); # 新版本5.16用 __SUB__->($sub, $v);
} else {
$v = $sub->($v);
}
}
}
my @array = (
[1, 2, 3],
[ [4,5,6], [7,8,9]],
[ [ [ 1,2,3],[4,5,6] ], [ [7,8,9], [1,2,3]]],
);
forall sub { shift() * 2 }, \@array;
use Data::Dumper;
say Dumper \@array;
复制代码
这算基本的递归把,如果要在运行中改变数组的大小结果可能是未定义的
作者:
只是一个红薯
时间:
2013-08-21 16:44
闭包?
作者:
104359176
时间:
2013-08-21 19:27
回复
7#
只是一个红薯
闭包是在固定的一个上下文环境中定义的代码块或函数。如果需要在动态的调用环境中使用上下文的环境,函数该如何实现呢?
作者:
104359176
时间:
2013-08-21 19:32
回复
6#
zhlong8
这个实现了遍历数据结构,如果对遍历出的数据进行处理完后,再保存回去的话,怎么办呢?
我设计了个迭代器,有个当前的迭代状态信息,可以调用这个信息,获取当前位置的定位信息。就能保存回去了。
1维数组只需要一个状态信息,2维就需要两个了。。
作者:
zhlong8
时间:
2013-08-21 19:34
回复
9#
104359176
这和第一个是一样的啊,就是直接修改原来的数组每一维都是
作者:
zhlong8
时间:
2013-08-21 19:36
回复
9#
104359176
Perl 的 for (LIST) {} 循环循环变量相当于别名,对循环变量赋值就是直接修改数组,包括 values $_ *= 2 for values %hash; 就是 %hash 里的值都 x2 在保存到原来的位置
作者:
104359176
时间:
2013-08-21 19:47
回复
11#
zhlong8
是的,利用这个特性可以简化这个模型,但通过函数的副作用来改变一个变量是一种危险的行为,因为这个特性不是所有的语言都有,尤其在函数式编程中,这种特性被认为是错误的。我不想把代码构筑在一些和语言相关的特性上,因为这些特性可能是一个设计错误。
作者:
zhlong8
时间:
2013-08-21 20:58
回复
12#
104359176
既然你懂lisp就应该明白抽象出来个 forall 这个概念就足够了,每种语言怎么实现和你的任务并没什么关系。
作者:
ttcn_cu
时间:
2013-10-12 16:13
怎么遍历就怎么存啊,这是任何函数编程的基本功
#!perl
use strict;
use warnings;
use Data:
umper;
my $Array = [
[1, 2, 3],
[ [4,5,6], [7,8,9]],
[ [ [ 1,2,3],[4,5,6] ], [ [7,8,9], [1,2,3]]],
];
my $Sub_Traverse;
my $Sub_Oparator=sub{
return $_++;
};
$Sub_Traverse=sub{
my $Arg_ = shift;
my $Oper_ = shift;
my $R_=[];
for (@$Arg_){
if (ref $_ eq 'ARRAY') {
push $R_,$Sub_Traverse->($_,$Oper_);
}
else {
$Oper_->($_);
push $R_,$_;
}
}
return $R_;
};
print Dumper $Sub_Traverse->($Array,$Sub_Oparator);
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2