编程时多多思考吧,别光掌握perl的古怪用法而不理解其精髓!

下面再来看看 grep:

[Copy to clipboard] [ - ]
CODE:
flw@debian:~/perl-5.9.5$ cat ttt.pl
@b=(70,80,90);
#@a = map { $_/10 } @b;
@a = grep { $_==80 } @b;
#@a = sort sub { $b<=>$a }, @b;
flw@debian:~/perl-5.9.5$ ./perl -Dtls ttt.pl
(ttt.pl:0)      ENTER scope 2 at perly.c:351
(ttt.pl:3)      ENTER scope 3 at op.c:7795
(ttt.pl:3)      LEAVE scope 3 at op.c:8390
(ttt.pl:4)      ENTER scope 3 at op.c:7795
(ttt.pl:3)      LEAVE scope 3 at op.c:8390
(ttt.pl:4)      LEAVE scope 2 at perly.c:680
(ttt.pl:0)      LEAVE scope 1 at perl.c:2304
(ttt.pl:0)      ENTER scope 1 at perl.c:2312
(ttt.pl:0)      popping jumplevel was bf8ab200, now 82122a0
(ttt.pl:0)      Setting up jumplevel bf8ab20c, was 82122a0

EXECUTING...

(ttt.pl:0)      Entering new RUNOPS level
    =>
(ttt.pl:0)      enter
(ttt.pl:0)      ENTER scope 2 at pp_hot.c:1712
Entering block 0, type BLOCK
    =>
(ttt.pl:0)      nextstate
    =>
(ttt.pl:1)      pushmark
    =>  *
(ttt.pl:1)      const(IV(70))
    =>  *  IV(70)
(ttt.pl:1)      const(IV(80))
    =>  *  IV(70)  IV(80)
(ttt.pl:1)      const(IV(90))
    =>  *  IV(70)  IV(80)  IV(90)
(ttt.pl:1)      pushmark
    =>  *  IV(70)  IV(80)  IV(90)  *
(ttt.pl:1)      gv(main::b)
    =>  *  IV(70)  IV(80)  IV(90)  *  GV()
(ttt.pl:1)      rv2av
    =>  *  IV(70)  IV(80)  IV(90)  *  AV()
(ttt.pl:1)      aassign
    =>
(ttt.pl:1)      nextstate
    =>
(ttt.pl:3)      pushmark
    =>  *
(ttt.pl:3)      pushmark
    =>  **
(ttt.pl:3)      gv(main::b)
    =>  **  GV()
(ttt.pl:3)      rv2av
    =>  **  IV(70)  IV(80)  IV(90)
(ttt.pl:3)      grepstart
(ttt.pl:3)      ENTER scope 3 at pp_ctl.c:933
(ttt.pl:3)      ENTER scope 4 at pp_ctl.c:940
    =>  **  IV(70)  **  IV(80)  IV(90)
(ttt.pl:3)      gvsv(main::_)
    =>  **  IV(70)  **  IV(80)  IV(90)  IV(70)
(ttt.pl:3)      const(IV(80))
    =>  **  IV(70)  **  IV(80)  IV(90)  IV(70)  IV(80)
(ttt.pl:3)      eq
    =>  **  IV(70)  **  IV(80)  IV(90)  SV_NO
(ttt.pl:3)      scope
    =>  **  IV(70)  **  IV(80)  IV(90)  SV_NO
(ttt.pl:3)      grepwhile
(ttt.pl:3)      LEAVE scope 4 at pp_hot.c:2336
(ttt.pl:3)      ENTER scope 4 at pp_hot.c:2366
    =>  **  IV(70)  *  IV(80)  *  IV(90)
(ttt.pl:3)      gvsv(main::_)
    =>  **  IV(70)  *  IV(80)  *  IV(90)  IV(80)
(ttt.pl:3)      const(IV(80))
    =>  **  IV(70)  *  IV(80)  *  IV(90)  IV(80)  IV(80)
(ttt.pl:3)      eq
    =>  **  IV(70)  *  IV(80)  *  IV(90)  SV_YES
(ttt.pl:3)      scope
    =>  **  IV(70)  *  IV(80)  *  IV(90)  SV_YES
(ttt.pl:3)      grepwhile
(ttt.pl:3)      LEAVE scope 4 at pp_hot.c:2336
(ttt.pl:3)      ENTER scope 4 at pp_hot.c:2366
    =>  **  IV(80)  IV(80)  *  IV(90)  *
(ttt.pl:3)      gvsv(main::_)
    =>  **  IV(80)  IV(80)  *  IV(90)  *  IV(90)
(ttt.pl:3)      const(IV(80))
    =>  **  IV(80)  IV(80)  *  IV(90)  *  IV(90)  IV(80)
(ttt.pl:3)      eq
    =>  **  IV(80)  IV(80)  *  IV(90)  *  SV_NO
(ttt.pl:3)      scope
    =>  **  IV(80)  IV(80)  *  IV(90)  *  SV_NO
(ttt.pl:3)      grepwhile
(ttt.pl:3)      LEAVE scope 4 at pp_hot.c:2336
(ttt.pl:3)      LEAVE scope 3 at pp_hot.c:2343
    =>  *  IV(80)
(ttt.pl:3)      pushmark
    =>  *  IV(80)  *
(ttt.pl:3)      gv(main::a)
    =>  *  IV(80)  *  GV()
(ttt.pl:3)      rv2av
    =>  *  IV(80)  *  AV()
(ttt.pl:3)      aassign
    =>
(ttt.pl:3)      leave
(ttt.pl:0)      POPBLOCK scope 2 at pp_hot.c:1814
Leaving block 0, type BLOCK
(ttt.pl:0)      LEAVE scope 2 at pp_hot.c:1853
(ttt.pl:0)      leaving RUNOPS level
(ttt.pl:0)      popping jumplevel was bf8ab20c, now 82122a0
(ttt.pl:0)      Setting up jumplevel bf8ab200, was 82122a0
(ttt.pl:0)      popping jumplevel was bf8ab200, now 82122a0
(ttt.pl:0)      LEAVE scope 1 at perl.c:567
flw@debian:~/perl-5.9.5$

和 map 类似,callback 将最后一句的执行结果,用 SV_YES 和 SV_NO 的形式压入堆栈,
grepwhile 将其弹出,然后判断,根据情况,修改 destination list。
grepwhile 的实现比 map/sort 都要简单得多,下面是全部代码:

[Copy to clipboard] [ - ]
CODE:
2329 PP(pp_grepwhile)
2330 {
2331     dVAR; dSP;
2332
2333     if (SvTRUEx(POPs))
2334         PL_stack_base[PL_markstack_ptr[-1]++] = PL_stack_base[*PL_markstack_ptr];
2335     ++*PL_markstack_ptr;
2336     LEAVE;                                      /* exit inner scope */
2337
2338     /* All done yet? */
2339     if (PL_stack_base + *PL_markstack_ptr > SP) {
2340         I32 items;
2341         const I32 gimme = GIMME_V;
2342
2343         LEAVE;                                  /* exit outer scope */
2344         (void)POPMARK;                          /* pop src */
2345         items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
2346         (void)POPMARK;                          /* pop dst */
2347         SP = PL_stack_base + POPMARK;           /* pop original mark */
2348         if (gimme == G_SCALAR) {
2349             if (PL_op->op_private & OPpGREP_LEX) {
2350                 SV* const sv = sv_newmortal();
2351                 sv_setiv(sv, items);
2352                 PUSHs(sv);
2353             }
2354             else {
2355                 dTARGET;
2356                 XPUSHi(items);
2357             }
2358         }
2359         else if (gimme == G_ARRAY)
2360             SP += items;
2361         RETURN;
2362     }
2363     else {
2364         SV *src;
2365
2366         ENTER;                                  /* enter inner scope */
2367         SAVEVPTR(PL_curpm);
2368
2369         src = PL_stack_base[*PL_markstack_ptr];
2370         SvTEMP_off(src);
2371         if (PL_op->op_private & OPpGREP_LEX)
2372             PAD_SVl(PL_op->op_targ) = src;
2373         else
2374             DEFSV = src;
2375
2376         RETURNOP(cLOGOP->op_other);
2377     }
2378 }

grep 的 callback 除了将结果压入堆栈之外,没有修改任何其它数据,更不用说受上一次调用的影响了,
因此不能算 closure。
饿。。。。难得又见flw老大发威了
上面东西真长

grep这种怎么看也是明显的回调,干嘛要以闭包理解,莫测
况且,闭包closure不能用回调?那是谁规定的?
看起来像闭包(或许),然后就说闭包,然后把回调封杀
顺便乱骂人一通,哎哟哟,伤脑筋啊

也许有人用了一辈子闭包,还不知道中间可能会有回调呢
这种人大概叫做

[Copy to clipboard] [ - ]
CODE:
!$perler

恩,这个语法不错
发飚了
flw,一直是偶比较喜欢的技术人


QUOTE:
原帖由 flw 于 2007-8-27 20:45 发表
grep map sort 的第一个参数就是回调函数,不是什么闭包,也不需要回避这个问题。

flw这个态度还是不错的,至少可以坚持自己认为是正确的观点!但是你们perler内部意见不统一,你不如先说服他们,然后,我再和你讨论,hehe!
TO flw:
你警告我说这贴是水贴,那我就编辑掉了,不过25楼、26楼似乎也是水贴,希望你也警告他们一下。

TO flw:
你警告我说这贴是水贴,那我就编辑掉了,不过25楼、26楼似乎也是水贴,希望你也警告他们一下。

就把函数当第一类的东西也就行了
闭包很难理解么?
要说数学概念,我等程序员就别扯淡了
用起来,就照着函数式走就好了嘛


QUOTE:
原帖由 shhgs 于 2007-9-20 06:40 发表
closure可以当回调用,但是closure最大的功能是访问数据。说map,grep,sort里面有callback一点都不意外,但是说它们不是closure,只能说明你根本不懂closure。


%d =();
{
   my $var = 7;
   sub a {
...

哇哇,其实还是一直很佩服shhgs的技术的,虽然他一直反对perl(当然,是从信仰角度,这样就不难理解了)
不过区区也觉得,shhgs这里明显使用了grep的callback
而sub a作为一个闭包,被拿进grep回调的block{}里面使用了
只能说grep可以调用闭包,而不是说grep本身属于闭包
你写那么复杂,直接写个%7,这和闭包还有任何牵扯?

ps. 实在看不惯lz那个态度,你那么说大家,你至少自己给点说法啊
   什么都不说,你凭什么BS大家,凭自己的“无知”?
   抱歉,如果“无知”用的不妥,请指出


QUOTE:
原帖由 shhgs 于 2007-9-20 06:40 发表
grep是不是通过调用这个block访问到了它的作用域之外的数据了?这个block难道不是closure吗?

在你举的两个例子当中,
grep 的第一个参数都位于 %d 和 sub a 的作用域之内,
能够访问它们有什么奇怪的?
这就好比任何语言的函数体代码都可以访问全局变量一样。