2

У меня есть эта строка кода на игрушечном языке. Функция print -функция принимает список аргументов и печатает их.Что будет печатать при вызове по имени и по умолчанию?

print(a, (a := 5, a))

Будут ли разница в производительности, если я использовал вызов по значению или вызов по имени? Если да, то какими будут результаты.

Можно указать, что a инициализирован до 0.

+2

Зависит от реализации 'print' – Bergi

+0

Какова ваша позиция в этом вопросе? Какой материал по стратегиям оценки вы читали, что еще неясно? – Bergi

+0

Я пишу компилятор для проекта, и кто-то сказал мне, что при вызове по-имени он будет печатать '0 5', тогда как по позывным он будет печатать' 5 5'. Его аргумент заключался в том, что при вызове по значению он сначала оценил бы все выражения и впоследствии распечатал результаты. Есть ли правда в этом? – Borimino

ответ

4

С «вызов по значению» аргументы обычно вычисляются слева направо (в большинстве языков), так что выражение будет эквивалентно что-то вроде этого:

arg1 := a // copy value of a to arg1 
a := 5 // copy 5 to a 
arg2 := a // copy value of a to arg2 
print(arg1, arg2) // print(0, 5) 

«по призванию по имени», по-видимому форма отложенной оценки, которая даст что-то вроде этого:

arg1 := function() {return a;} 
arg2 := function() {a := 5; return a;} 
print(arg1, arg2) 

Так что в этом случае результат будет зависеть от двух вещей:

  • ли на этом языке замыкания захватывают переменные по ссылке или по значению. Если захват по значению, a := 5 не повлияет на значение a, которое зафиксировало первое закрытие. Однако большинство языков, которые позволяют переназначить локальные переменные, реализуют захват по ссылке (например, JavaScript).
  • Порядок, в котором функция print решает оценить свои аргументы, зависит от того, как она написана.

Если захват укупорочные по значению, print(…) даст 0 5, поскольку присваивание a := 5 влияет только на копию второго закрытия по a.

Если затворы захватываются ссылкой, я могу только догадываться, на каком выходе. Но вполне вероятно, функция print будет делать что-то вроде этого:

print := function(lazy x, lazy y) { 
    writeToOutput(x()) 
    writeToOutput(y()) 
} 

В этом случае результат будет таким же (0 5), потому что x() оцениваются первым, результат обрабатывается, а затем y() оцениваются. В этом случае значение a не изменяется до тех пор, пока функция не будет выполнена с x.

Но это только догадка; print может оценивать их в любом порядке (и любое количество раз).

+0

"аргументы обычно оцениваются слева направо (на большинстве языков). Известными примерами счетчиков являются C, C++ и OCaml. В этих языках порядок оценки аргументов функции не указан (и часто реализуется как справа налево). – sepp2k

+1

@ sepp2k: также схема и друзья – rici