Почему этот код устанавливает переменную a в 9? - PullRequest
2 голосов
/ 16 июня 2019

Я смущен этим фрагментом кода:

| 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 ]

8 голосов
/ 16 июня 2019

Селектор 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.

2 голосов
/ 17 июня 2019

Я могу быть единственным, но второе предложение я нахожу немного неясным:

Однако так получилось, что c определяется как блок [a: = a- 2. b], который возвращает значение b и оказывается блоком. Итак timesRepeat: счастлив, и он выполняет блок b на каждой итерации, в которой a нечетно .

Семантика Smalltalk:

  1. Оценка получателя
  2. Оценка аргументов
  3. Отправка сообщения

порядок имеет решающее значение, потому что оценки могут иметь побочные эффекты.

Итак, на самом деле происходит:

  1. Получатель 10 оценивается как 10
  2. Аргумент a even ifTrue: b ifFalse: c оценивается в b.Побочный эффект a = -1.
  3. Сообщение 10 timesRepeat: b или 10 timesRepeat: [a := a + 1] отправляется

Следовательно, a = 9.

...