“地图”是一个循环?
在回答这个问题的时候 ,我意识到我不确定Perl的map
能否被认为是一个循环呢?
一方面,它像一个循环(O(n))工作,可以很容易地被一个等价的循环重写,并且符合通用定义=“连续重复的指令序列”。
另一方面, map
通常不在Perl的控制结构中列出,其中循环是其子集。 例如http://en.wikipedia.org/wiki/Perl_control_structures#Loops
所以,我正在寻找的是一个正确的理由相信一方与另一方。 到目前为止,前者(这是一个循环)对我来说听起来更加令人信服,但是由于我从来没有看到Perl循环列表中提到的“映射”,所以我感到困扰。
从函数式编程中借鉴地图是比循环更高层次的概念。 它没有说“从一开始到最后一个一个的调用这个函数”,它说“在所有这些项目上调用这个函数”。 它可能被实现为循环,但这不是重点 – 它也可能是asynchronous实现的 – 它仍然是地图。
另外,它本身并不是一个真正的控制结构 – 如果每个在其实现中使用循环的perl函数都被列在“循环”下面呢? 只是因为某些东西是用循环来实现的,并不意味着它应该被认为是它自己的循环types。
不,从我的angular度来看,这不是一个循环。
(perl)循环的特点是它们可以被分解( last
)或恢复( next
, redo
)。 map
不能:
map { last } qw(stack overflow); # ERROR! Can't "last" outside a loop block
错误消息表明perl本身并不考虑评估块是一个循环块 。
从学术的angular度来看,两种情况都可以根据地图的定义来制定。 如果它总是按顺序迭代,那么可以通过使两个等价的map
来模拟一个foreach
循环。 映射的一些其他定义可能会允许无序执行列表以实现性能(在线程或甚至单独的计算机之间划分工作)。 用foreach
构造也可以做到这一点。
但就Perl 5而言, map
总是按顺序执行的,使其等价于一个循环。 expression式map $_*2, 1, 2, 3
的内部结构导致以下执行顺序操作码,这些操作码显示map
在内部构build为类似于while
的控制结构:
OP enter COP nextstate OP pushmark SVOP const IV 1 SVOP const IV 2 SVOP const IV 3 LISTOP mapstart LOGOP (0x2f96150) mapwhile <-- while still has items, shift one off into $_ PADOP gvsv GV *_ SVOP const IV 2 loop body BINOP multiply goto LOGOP (0x2f96150) <-- jump back to the top of the loop LISTOP leave
map
函数不是Perl中的循环。 这可以清楚地看到, next
, redo
, last
在map
里面的失败:
perl -le '@a = map { next if $_ %2; } 1 .. 5; print for @a' Can't "next" outside a loop block at -e line 1.
要在map
实现所需的效果,您必须返回一个空列表:
perl -le '@a = map { $_ %2 ? () : $_ } 1 .. 5; print for @a' 2 4
我认为转型更适合像map
。 它将一个列表转换成另一个列表。 与map
类似的函数是List::Util::reduce
,但不是将列表转换为另一个列表,而是将列表转换为标量值。 通过使用单词转换,我们可以讨论这两个高阶函数的共同点。
也就是说,它通过访问列表中的每个成员来工作。 这意味着它的行为很像一个循环,取决于你所定义的“循环”是否有可能。 请注意,我的定义意味着这个代码中没有循环:
#!/usr/bin/perl use strict; use warnings; my $i = 0; FOO: print "hello world!\n"; goto FOO unless ++$i == 5;
Perl实际上在文档中定义了词汇循环 :
loop A construct that performs something repeatedly, like a roller coaster.
通过这个定义, map
是一个循环,因为它重复执行它的块; 但是,它也定义了“循环控制语句”和“循环标签”:
loop control statement Any statement within the body of a loop that can make a loop prematurely stop looping or skip an "iteration". Generally you shouldn't try this on roller coasters. loop label A kind of key or name attached to a loop (or roller coaster) so that loop control statements can talk about which loop they want to control.
我认为把map
作为一个循环是不准确的,因为next
和它的亲族被定义为循环控制语句 ,他们不能控制map
。
这一切都只是玩文字。 将map
描述为“一个循环”是将某人引入其中的完美方法。 即使map
的文档也使用foreach
循环作为其示例的一部分:
%hash = map { get_a_key_for($_) => $_ } @array; is just a funny way to write %hash = (); foreach (@array) { $hash{get_a_key_for($_)} = $_; }
这一切都取决于上下文。 当你试图让他或她理解这个概念时,把乘法形容为重复的加法是有用的,但是你不希望他或她继续这样想。 你会希望他或她学习乘法规则,而不是总是回到加法规则。
你的问题转向分类的问题。 至less在一种解释下,询问map
是否是一个循环,就像询问map
是否是“Loop”的一个子集。 这样的框架,我认为答案是否定的。 虽然map
和Loop有许多共同之处,但有重要的区别。
- 循环控制 : Chas。 Owens使得 Perl循环像
next
和last
一样受到循环控制,而map
不是。 - 返回值 :
map
的目的是它的返回值; 与循环,不是很多。
我们在现实世界中总是遇到类似这样的关系 – 彼此有许多共同之处,但既不是另一个完美的子集。
----------------------------------------- |Things that iterate? | | | | ------------------ | | |map() | | | | | | | | --------|---------- | | | | | | | | | | | | | | ------------------ | | | | | | | | Loop| | | ------------------ | | | -----------------------------------------
地图是一个高阶函数 。 这同样适用于grep。 预订高阶Perl详细解释了这个想法。
看到讨论转向实施细节,而不是概念,真是令人伤心。
FM和Dave Sherohman的答案相当不错,但是让我再添加一个看地图的方法。
地图是一个function, 保证只查看一次结构的每一个元素。 它不是一个控制结构,因为它本身是一个纯粹的function。 换句话说,映射蜜饯的不variables非常强大,比“一个循环”强得多。 所以,如果你可以使用地图,那就太好了,因为你可以免费得到所有这些不variables,而如果你使用的是一个(更一般的)控制结构,那么你必须自己build立所有这些不variables要确保你的代码是正确的。
这真是很多这些高阶函数的美妙之处:你可以免费获得更多的不variables,所以作为程序员的你可以花费宝贵的思考时间来维护依赖于应用程序的不variables,而不必担心低级的实现依赖的问题。
map
本身通常使用某种types的循环来实现(通常是循环迭代器),但由于它是一个更高级别的结构,因此它通常不包含在较低级别的控制结构列表中。
下面是地图的定义:
sub _map (&@) { my $f = shift; return unless @_; return $f->( local $_ = shift @_ ), _map( $f, @_ ); } my @squares = _map { $_ ** 2 } 1..100;
“循环”更多的是一个CS术语,而不是一个语言特定的术语。 如果具有以下特征,则可以合理地调用某个循环:
- 迭代元素
- 每次都做同样的事情
- 是
O(n)
map
适合这些非常密切,但它不是一个循环,因为它是一个更高层次的抽象。 可以说它具有循环的属性,即使它本身不是最严格的,最低级的意义上的循环。
我认为地图符合Functor的定义。
这一切都取决于你如何看待它…
一方面,Perl的map
可以被认为是一个循环,如果仅仅因为这是Perl(当前版本)中的实现。
另一方面,我认为它是一个functionmap
并select使用它,其中包括只作出列表的所有元素将被访问的假设,但不作任何假设的顺序他们将被访问。 除了function纯度之外,这带来并给出了一个存在的原因并被用来代替for
,这也使我保持良好的状态,如果一些未来版本的Perl提供了map
可并行化的实现。 (不是我对这种事情有任何期待…)
我认为地图更像是一个运算符,就像乘法一样。 你甚至可以把整数乘法看作是一个加法循环:)。 当然这不是一个循环,即使这样愚蠢地实施。 我也看到地图。
Perl中的映射是一个高阶函数,它将给定函数应用于数组的所有元素,并返回修改过的数组。
无论是使用迭代循环还是通过recursion或其他方式来实现,都是不相关的,没有指定的。
所以一个映射不是一个循环,尽pipe它可以用一个循环来实现。
如果忽略左值,Map只会看起来像一个循环。 你不能用for循环做到这一点:
print join ' ', map { $_ * $_ } (1 .. 5) 1 4 9 16 25