Chinaunix

标题: mlists一位大侠对上下文概念的阐述 [打印本页]

作者: 兰花仙子    时间: 2007-03-09 13:30
标题: mlists一位大侠对上下文概念的阐述
大家对Perl的上下文概念有所迷惑的,当认真读此前辈名言.

>@string_array = <STDIN>;
>
>@string_array = reverse(@string_array);
>print("\n@string_array\n");
>print("\n" . reverse(@string_array) . "\n");
>
>
>If this is run, the first print statement prints out the lines in the
>opposite order they were entered, however the second print statement
>reverses the entire line one at a time. I do not understand what is
>going on.


That is a very good question, and it goes right to the heart of a very important and unusual feature of the Perl language, so it'll take a little while to explain. Please bear with me through this explanation of one of Perl's central concepts.

Every Perl expression is in one of two `contexts', either `list context' or `scalar context', depending on whether it is expected to produce a list or a scalar. Many expressions have quite different behaviors in list context than they do in scalar context.

Here is a typical expression:

        EXPRESSION

Here it is again, in a list context:

        @array = EXPRESSION;   # Expression is expected to produce a list

Here is how it looks in a scalar context:

        $scalar = EXPRESSION;   # Expression is expected to produce a scalar

The values that a particular expression has in these two contexts might be quite different. For example, consider this simple expression:

        @q

In list context, this produces a list of the items in the array @q, but in scalar context it produces the number of items in the array @q.

        @a = @q;    # @q in list context produces a list of items from @q
        $s = @q;    # but in scalar context, it produces the number of items.

Similarly,

        # Note two very different behaviors of // depending on context

        # Put ('123.45', 'immediately') into @a
        @a = /The amount was \$(\d+\.\d\d)\.  You must pay ([\w\s]+)\./

        # Put 1 into $s, put '123.45' into $1, put 'immediately' into $2
        $s = /The amount was \$(\d+\.\d\d)\.  You must pay ([\w\s]+)\./

The main point here: An expression's behavior can be drastically different in list context than it is in scalar context.

Now we'll return to your example.


>     @string_array = reverse(@string_array);

Here, reverse is in list context, because it's being asked to produce a list to assign to @string_array. In list context, reverse reverses the order of its arguments, so that the lines come out in the reverse order.

Then you did

>    print("\n" . reverse(@string_array) . "\n");

Now, here reverse is in scalar context, because it is being asked to produce a scalar value, a string, which will be concatenated with \n on the front and back. In a scalar context, reverse first concatenates all its arguments, to get a single string, and then reverses that string. As you know by now.

How can you get the behavior you really want? The reverse here needs to be in a list context. The argument list of a function like `print' is always a list context, so if you get rid of the concatenation operators that are providing scalar context to `reverse', your problem will go away:

        print "\n", reverse(@string_array), "\n";

reverse is now expected to return a list, which will be inserted into the list which is passed to print. This is probably more efficient than what you were trying to do anyway, since print can print out the many strings without bothering to concatenate them first, as you were doing.

Again, the general rule is:

There is no general rule for deducing a function's behavior in scalar context from its behavior in list context.
This is the cause of a lot of common errors. One mistake you didn't make, but which we see a lot is something like this:

        @a = (reverse("part"));

The programmer was expecting @a to get a list containing "trap", but instead they got a list containing "part" again. Because reverse was in a list context, it reversed the order of its arguments, instead of reversing the arguments themselves, and since it only had one argument, it ended up doing nothing.

Perl has a special operator for just such circumstances. It's called scalar, and it forces its argument to be evaluated in scalar context. The last example should have been written as:

        @a = (scalar(reverse("part")));
        # @a now contains ("trap")

I hope this clears things up for you.



偶亦希望学Perl者,一定要弄清楚上下文这个基本概念.
作者: xuxingyu    时间: 2007-03-09 13:37
thanks 学习了
作者: 大大狗    时间: 2007-03-09 14:18
认真的读一下
作者: kid@B_Sky    时间: 2007-03-10 12:43
thanks very much
作者: penny_kan    时间: 2007-03-10 22:51
明白了表达的意思,只是不明白为什么会这样
print("\n" . reverse(@string_array) . "\n");
这一句居然reverse 了list本身顺序,因为分格符reverse 了 list中的元素倒是可以理解,
难道这个要强记下来么
作者: 兰花仙子    时间: 2007-03-10 23:57
原帖由 penny_kan 于 2007-3-10 22:51 发表
明白了表达的意思,只是不明白为什么会这样
print("\n" . reverse(@string_array) . "\n");
这一句居然reverse 了list本身顺序,因为分格符reverse 了 list中的元素倒是可以理解,
难道这 ...


没听明白,想要表达what?
作者: xiaoshengcaicai    时间: 2007-03-11 09:56
参考:
perl cookbook 2nd
Recipe 1.7 Reversing a String by Word or Character
作者: penny_kan    时间: 2007-03-11 12:45
原帖由 兰花仙子 于 2007-3-10 23:57 发表


没听明白,想要表达what?


print("\n" . reverse(@string_array) . "\n");
没明白这句为什么会把list与scalar都reverse一遍。
举例,如果代码是这样

@string_array = qw#how are you#;        

@string_array = reverse(@string_array);
print("\n@string_array\n");
print("\n" . reverse(@string_array) . "\n");


事实第二句的输出内容是
woherauoy
而我的理解是第二句应该输出为
uoyerawoh


~
作者: shhgs    时间: 2007-03-11 23:19
我好像没有义务教你们什么是上下文。

[ 本帖最后由 shhgs 于 2008-1-24 21:45 编辑 ]
作者: 兰花仙子    时间: 2007-03-12 18:40
原帖由 penny_kan 于 2007-3-11 12:45 发表


print("\n" . reverse(@string_array) . "\n");
没明白这句为什么会把list与scalar都reverse一遍。
举例,如果代码是这样



事实第二句的输出内容是
woherauoy
而我的理解是第二 ...



这是因为reverse这个函数本身区分上下文环境.不同上下文返回值不同.
from perldoc -f reverse:
       reverse LIST
               In list context, returns a list value consisting of the elements of LIST in the opposite order.  In scalar
               context, concatenates the elements of LIST and returns a string value with all characters in the opposite
               order.

                   print reverse <>;           # line tac, last line first

                   undef $/;                   # for efficiency of <>
                   print scalar reverse <>;    # character tac, last line tsrif

作者: hutule110    时间: 2007-03-13 10:33
受教了,谢谢
作者: flw    时间: 2007-03-13 10:44
看不懂,仙子给翻译下。
作者: penny_kan    时间: 2007-03-13 23:55
谢谢仙女,都不明白当初怎么想的了,现在怎么看这个结果都没问题的

我的理解是:

print("\n" . reverse(@string_array) . "\n";

显示"woherauoy" 的理由上下文决定这是个scalar了,所以list中的所有字符均被串成一个scalar, 然后reverse。

这样对比显示一下可能明白一点
print("\n" . reverse(@string_array) . "\n";
print("\n" , (@string_array) , "\n";

作者: Cocory    时间: 2008-01-24 18:08
print("\n" . reverse(@string_array) . "\n";

既然reverse处于scalar context下,那@string_array应该返回数组长度才更合理啊?有没有高手进一步解释一下。
作者: Cocory    时间: 2008-01-24 19:47
翻了翻《Perl语言入门》,找到了答案。

  1. 有许多表达式通常都是产生列表的。当其在标量context 中使用时,会得到什么结果呢?让我们看看这个操作的创始人怎么
  2. 解释的。通常,这个人是Larry,其文档展现了整个历史。对于Perl 的学习,大部分是学习Larry 是怎么的想的◆。因此,
  3. 一旦你能像Larry 那样思考时,你就能明白Perl 的行为。当学习时,你可能需要查看其文档。
  4.     ◆更准确的说,Larry 创建Perl 时,是按照你希望它怎样操作来设计的。

  5. 一些表达式根本没有标量context 的值。例如,sort 在标量context 中返回什么?你不需要要排序一个列表来得到其个数,因
  6. 此,除非有人按另一种方式实现了sort,否则其在标量context 中返回undef。
  7. 另一个例子是reverse。在列表context 中,它返回反转的列表。在标量context 中,返回反转的字符串(或者将反转的结果串
  8. 成一个字符串):
复制代码


我觉得可以这么理解表达式在特定上下文中的求值规则:一般情况下,依靠所谓的expected值来决定上下文;如果需要运用perl,也就是Larry本人的设计哲学时,则从该哲学出发。
作者: 兰花仙子    时间: 2008-01-24 23:30
有许多表达式通常都是产生列表的。当其在标量context 中使用时,会得到什么结果呢?让我们看看这个操作的创始人怎么
解释的。通常,这个人是Larry,其文档展现了整个 ...


习惯就好了.什么语言都有易混淆之处的.
经常有人批评perl的上下文,其实python不也同样有这个概念...

def test(a,b,c):
    return a,b,c

到底是return一个tuple还是三个object呢?

x=test(1,2,3)
x,y,z=test(1,2,3)

2个x值不同,当然可以说后者是unpack一个tuple,但如果说perl的上下文让人混淆,python这里也好不了多少.
作者: Cocory    时间: 2008-01-25 10:09
原帖由 兰花仙子 于 2008-1-24 23:30 发表


习惯就好了.什么语言都有易混淆之处的.
经常有人批评perl的上下文,其实python不也同样有这个概念...

def test(a,b,c):
    return a,b,c

到底是return一个tuple还是三个object呢?

x=test(1,2,3) ...



不过我认为Larry在这一点上还是使用了某种违反直觉的“哲学”,呵呵。

总体,来说,Larry的哲学还是很务实,很让程序员喜欢的。

也许,是我的悟性不够,估计等我真正认同关于sort,reverse的默认行为背后的哲学思想时,我就跨入高手行列了。
作者: shhgs    时间: 2008-01-25 11:31
不知道能不能回帖。
作者: shhgs    时间: 2008-01-25 11:40
原帖由 兰花仙子 于 2008-1-24 23:30 发表


习惯就好了.什么语言都有易混淆之处的.
经常有人批评perl的上下文,其实python不也同样有这个概念...

def test(a,b,c):
    return a,b,c

到底是return一个tuple还是三个object呢?

x=test(1,2,3) ...



Perler在这种鸡蛋里挑骨头的领域一向是很有创意的。不过胡说八道永远是胡说八道。


  1. def test(a,b,c):
  2.     return a,b,c
复制代码

告诉你,这里返回一个tuple。tuple本身就是一个object,这个总应该知道吧。


  1. x= test(1,2,3)
复制代码

x是一个tuple。没意见吧。explicit吧。


  1. a, b, c= test(1, 2, 3)
  2. x = test(1, 2, 3)
  3. a, b, c = x
复制代码

有什么混淆的?有什么不明白的?还有什么骨头能挑?

Perl有问题,不但不承认,还一知半解地去曲解Python。这就是Perler的态度?
作者: shhgs    时间: 2008-01-25 11:43
更准确的说,Larry 创建Perl 时,是按照你希望它怎样操作来设


好像这就是我说的,强迫你接受Larry的想法。但问题是,他的想法对吗?
作者: apile    时间: 2008-01-25 11:57
其实语言就是这样..接不接受看自己...

shhgs不接受的话..也没差..

但是你在这里一直讲..人家就会觉得你很烦...就算你有道理..久了也就会被认为没道理了...

我认为你讲的很有道理...
,reserve(), 与 . reserve() .   这种写法..本来就很容易让人混淆...我从来不会这麽写程序..

只是我只当perl是我解决问题的工具...不是要拿来膜拜的对象...

语言有问题是很正常的...全世界哪种语言没问题?如果没问题..为什麽还要出新版本..

大家请继续...
作者: hitsubunnu    时间: 2008-01-28 12:16
原帖由 shhgs 于 2008-1-25 11:43 发表


好像这就是我说的,强迫你接受Larry的想法。但问题是,他的想法对吗?


[ 本帖最后由 hitsubunnu 于 2008-1-28 13:34 编辑 ]
作者: orangetouch    时间: 2008-01-28 13:36
这个问题说是上下文的问题,不如说是reverse的问题。reverse确实是设计得不好的一个函数。

反转一个字符串和反转一个LIST本身就是两种不同的操作,非要用一个函数来示。

这也罢了,而且更怪的是做哪种操作不是由参数来决定的,而是由所要求的返回值来决定的。

[ 本帖最后由 orangetouch 于 2008-1-28 16:32 编辑 ]
作者: afoxwwk    时间: 2008-01-29 11:21
原帖由 shhgs 于 2008-1-25 11:43 发表


好像这就是我说的,强迫你接受Larry的想法。但问题是,他的想法对吗?




此人人品有问题,鉴定完毕!

非常同意apile的看法。
:wink:
作者: shhgs    时间: 2008-01-29 13:28
原帖由 orangetouch 于 2008-1-28 13:36 发表
这个问题说是上下文的问题,不如说是reverse的问题。reverse确实是设计得不好的一个函数。

反转一个字符串和反转一个LIST本身就是两种不同的操作,非要用一个函数来示。

这也罢了,而且更怪的是做哪种操作 ...



能讲这话的Perler不多。人品没问题。

不过你还是没搞懂上下文。根据返回值决定函数的实现,也是上下文的一种形式。

至于上下文到底是什么。Sorry,真是讲不清楚。连Randy Shawtz在Learning Perl里面都说没人能讲清楚,你也就不用追根寻底了。如果有谁想追问上下文到底是什么。我倒是可以给你预测一下你将得到的答案。Perler权威先万分鄙视地给你一个半瓶醋的鉴定,再华丽地ignore你。然后,兴高采烈地宣称,这东西很容易,很清楚,很explicit,很符合人类理性,很Perl。

[ 本帖最后由 shhgs 于 2008-1-29 13:51 编辑 ]
作者: shhgs    时间: 2008-01-29 13:33
原帖由 afoxwwk 于 2008-1-29 11:21 发表




此人人品有问题,鉴定完毕!

非常同意apile的看法。
:wink:



病人姓名: afoxwwk
症状: 高度妄想狂
诊断意见: 不能出院

医生签名: shhgs
作者: nm_0011    时间: 2008-05-08 16:02
这不是很简单么?
@stray=qw(thank you);
@stray=reverse(@stray); // reverse 处于list上下文下,是将列表中的各项的顺序倒置,得到 you thank
printf("@stray"); // 输出you thank
printf("\n".reverse(@stray)."\n"); reverse 处于scalar上下文下,是将you thank 先转换为字符串再将字符串倒置,得到knahtuoy。
作者: perlxingshou    时间: 2008-05-08 19:27
原帖由 shhgs 于 2008-1-29 13:28 发表



能讲这话的Perler不多。人品没问题。

不过你还是没搞懂上下文。根据返回值决定函数的实现,也是上下文的一种形式。

至于上下文到底是什么。Sorry,真是讲不清楚。连Randy Shawtz在Learning Perl里面 ...

你懂个猫啊
作者: qishking    时间: 2008-10-28 16:37
原帖由 nm_0011 于 2008-5-8 16:02 发表
这不是很简单么?
@stray=qw(thank you);
@stray=reverse(@stray); // reverse 处于list上下文下,是将列表中的各项的顺序倒置,得到 you thank
printf("@stray"); // 输出you thank
printf("\n".reverse(@stray)."\n"); reverse 处于scalar上下文下,是将you thank 先转换为字符串再将字符串倒置,得到knahtuoy。

正解
作者: shilin320    时间: 2010-08-02 21:50
学习了,
谢谢
作者: beyondfly    时间: 2010-08-02 22:45
学习了
作者: Wayne_sama    时间: 2010-08-03 09:55
有点意思~~~学习了{:3_189:}
作者: 2gua    时间: 2010-08-03 12:38
上下文的理解,对学习和理解Perl来讲至关重要!
作者: snriyt    时间: 2010-08-05 10:27
学习了
作者: shilin320    时间: 2010-08-05 14:11
回复 27# nm_0011


    为什么我的输出不是这个结果啊?
作者: ztkx    时间: 2010-08-12 00:53
回复 1# 兰花仙子

  1. print("\n" . reverse(@string_array) . "\n");
  2. print "\n" , reverse(@string_array) . "\n";
复制代码
刚看到的,学习了,但是我在我这里试了一下,不同的操作系统是不一样的

debian下,正如前面的讨论
但是在win7下,两者都是作为scalar的,返回"woHerAuoY"
作者: xiaobing927    时间: 2010-08-12 15:17
这不是很简单么?
@stray=qw(thank you);
@stray=reverse(@stray); // reverse 处于list上下文下,是将列 ...
nm_0011 发表于 2008-05-08 16:02



说的非常透彻,“上下文”我的理解就是学语文时常说的语境,就是某个词语在特定语境的意思不一样。

比如:
1、好兄弟见面,“我操,你小子这么多年干什么去了,也不联系”
2、别人忽你一巴掌,“我操,你他M找死”




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2