为什么此代码将变量a设置为9?

时间:2019-06-15 22:10:11

标签: loops variables smalltalk parity

我对这段代码感到困惑:

| a b c| a := 1. b := [a := a + 1]. c := [a := a - 2. b].
        10 timesRepeat: (a even ifTrue: b ifFalse: c). a

我的假设是这段代码会将a设置为-19。每次迭代都会测试a是否为偶数,但是a将是奇数,因此将调用c,并从2中减去a而不会影响其奇偶性。 c不会调用b,因为如果我对块的理解正确,则将返回块的最后一个元素,而不是求值;因此c将返回b,但是timesRepeat会丢弃返回的任何内容,因此b中的c无效。

事实证明,我的假设是错误的:这段代码将a设置为9。为了查看发生了什么,我对这段代码做了一些修改:

| a b c| a := 1. b := [Transcript show: (a displayString). a := a + 1]. c := [Transcript  show: (a displayString). a := a - 2. b.].
           10 timesRepeat: (a even ifTrue: b ifFalse: c). a

这是打印出来的内容:

1-1012345678

所以看来b 被调用了吗?我的假设是否错误,即返回b而不是调用?

让我们尝试检查一下:

jkl := [Transcript show: 'I am called too.'].
asdf := [Transcript show: 'I am called!'. jkl].

10 timesRepeat: asdf

不是,asdf在这里没有呼叫jkl

I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!

无论如何,如果c始终只是调用b,则其效果是有效地从1中减去a;但这不会发生。取而代之的是,第一次迭代似乎调用了c,然后神秘地,即使b是奇数,每次迭代似乎都调用了a

这是怎么回事?

2 个答案:

答案 0 :(得分:8)

timesRepeat:选择器想要一个块作为参数。您正在用括号内的表达式来调用它:

10 timesRepeat: (a even ifTrue: b ifFalse: c).

尽管如此,c被定义为块[a := a - 2. b],该块返回b的值,并且恰好是一个块。因此timesRepeat:很高兴,并且它在b为奇数的每次迭代中执行块a。如果正确编写为:

10 timesRepeat: [a even ifTrue: b ifFalse: c].

然后最后,a将为-19。

关于您的陈述:如果我对块的理解是正确的,则返回块的最后一个元素而不是求值,实际上并非如此。块中的最后一条语句没有特殊处理,除了它的结果确实在执行该块时作为该块的值返回之外。您在块中的最后一条语句只是变量的名称。变量的值恰好是一个块,但是无论它是什么,只要在Smalltalk中仅具有一个变量名作为语句就可以返回变量的值。如果变量恰好是一个块,则可以得到该块。该块未执行。

请考虑以下块:

[a := 1. b := 2. c := a+b]

执行此块时,a的值为1,b的值为2,c的值为3。该块将返回的值为c,即3。

[a := 1. b := 2. a]

如果执行此块,结果将是a的值为1。

[a := 1. b := 2. c := [a+b]. c]

如果执行此块,结果将是变量c所代表的块。它不执行块c。这与前面的示例一致。

因此,当您执行块[Transcript show: 'I am called!'. jkl].时,将不执行末尾的jkl。它的值刚刚返回。如果要执行它,则可以编写asdf := [Transcript show: 'I am called!'. jkl value].,在发送value消息时将执行一个块。执行块[Transcript show: 'I am called!'. jkl value].的结果将是执行块jkl的结果。

答案 1 :(得分:2)

我可能是唯一的一个,但是我发现下面的第二句话有些晦涩:

  

尽管如此,但是c定义为块[a:= a-2。b],该块返回b的值并且恰好是一个块。 So timesRepeat:很高兴,并且它在每次是奇数的迭代中执行块 b 。 / p>

Smalltalk的语义是:

  1. 评估接收者
  2. 计算参数
  3. 发送消息

顺序很关键,因为评估可能会有副作用。

所以,实际发生的是:

  1. 接收者10的评估结果为10
  2. 参数a even ifTrue: b ifFalse: c的值为b。副作用a = -1
  3. 已发送消息10 timesRepeat: b10 timesRepeat: [a := a + 1]

因此,a = 9