Что такое "передача по имени" и как она работает?
Я проверил Википедию и погуглил, но все еще не могу понять, как работает логин в Алголе 60.
9 ответов
Я нашел хорошее объяснение при передаче параметров по имени. По сути, тело функции интерпретируется во время вызова после текстовой подстановки фактических параметров в тело функции. В этом смысле метод оценки аналогичен методу препроцессора Си.
Подставляя фактические параметры в тело функции, тело функции может как читать, так и записывать данные параметры. В этом смысле метод оценки похож на передачу по ссылке. Разница заключается в том, что, поскольку при передаче по имени параметр оценивается внутри функции, такой параметр, как a[i]
зависит от текущей стоимости i
внутри функции, а не ссылаясь на значение в a[i]
до того, как функция была вызвана.
На странице, на которую я ссылался выше, есть еще несколько примеров, когда передача по имени полезна и опасна. Методы, которые стали возможными благодаря передаче по имени, сегодня в значительной степени заменены другими, более безопасными методами, такими как функции передачи по ссылке и лямбда-функции.
Я предполагаю, что вы имеете в виду вызов по имени в Алголе 60.
Call-by-name похож на call-by-reference тем, что вы можете изменить значение переданного параметра. Он отличается от вызова по ссылке тем, что параметр не оценивается до вызова процедуры, а оценивается лениво. То есть он оценивается тогда и только тогда, когда параметр фактически используется.
Например, предположим, у нас есть процедура f(x, y)
и мы передаем это i
а также i/2
где i
изначально равен 10
, Если f
наборы x
в 42
а затем оценивает y
это увидит ценность 21
(тогда как при вызове по ссылке или вызове по значению он все равно увидит 5
). Это потому что выражение i/2
не оценивается до y
оценивается.
Во многих отношениях это похоже на буквальную текстовую подстановку параметров (с переименованием, чтобы избежать конфликтов имен). На практике, однако, это реализуется с использованием "thunks" (в основном замыканий) для переданных выражений.
Статья в Википедии об устройстве Дженсена показывает несколько интересных примеров использования вызова по имени. Вот один из них:
real procedure Sum(k, l, u, ak) value l, u; integer k, l, u; real ak; comment k and ak are passed by name; begin real s; s := 0; for k := l step 1 until u do s := s + ak; Sum := s end;
В процедуре индексная переменная
k
и срок суммированияak
передаются по имени. Вызов по имени позволяет процедуре изменить значение индексной переменной во время выполнения цикла for. Звонок по имени также вызываетak
Аргумент должен быть переоценен во время каждой итерации цикла. Как правило,ak
будет зависеть от изменения (побочный эффект)k
,Например, код для вычисления суммы первых 100 членов реального массива
V[]
было бы:Sum(i, 1, 100, V[i]).
Для тех, кто в будущем:
Понятия в Языках программирования Джоном К. Митчеллом были также полезны.
Передача по имени. Возможно, самая странная особенность Algol 60, в ретроспективе, это использование пароля по имени. При передаче по имени результат вызова процедуры такой же, как если бы формальный параметр был подставлен в тело процедуры. Это правило для определения результата вызова процедуры путем копирования процедуры и замены формальных параметров называется правилом копирования Algol 60. Хотя правило копирования хорошо работает для чисто функциональных программ, что иллюстрируется сокращением β в лямбда-исчислении, взаимодействие с побочными эффектами формального параметра немного странно. Вот пример программы, показывающей технику, называемую устройством Дженсена: передача выражения и содержащейся в нем переменной в процедуру, чтобы процедура могла использовать один параметр для изменения местоположения, на которое ссылается другой:
begin integer i; integer procedure sum(i, j); integer i, j; comment parameters passed by name; begin integer sm; sm := 0; for i := 1 step 1 until 100 do sm := sm + j; sum := sm end; print(sum(i, i*10 )) end
В этой программе процедура sum(i,j) суммирует значения j при переходе от 1 к 100. Если вы посмотрите на код, вы поймете, что процедура не имеет смысла, если только изменения i не вызовут некоторое изменение в значение j; в противном случае процедура просто вычисляет 100*j. В показанной здесь сумме вызовов (i, i*10) цикл for в теле суммы процедуры суммирует значение i * 10 при переходе от 1 к 100.
На самом деле, по имени, это не просто историческое любопытство. Вы можете выполнять вызов по имени в пакетных файлах Windows (и множестве других языков сценариев). Знание того, как это работает, и того, как эффективно использовать его в программировании, может помочь найти решение проблем. Я знаю, что он только пропускает строки для последующего расширения, но им можно манипулировать, чтобы иметь эффект, подобный call-by-name.
call :assign x 1
exit /b
:assign
setlocal enabledelayedexpansion
(endlocal
:: Argument 1 is the name of the variable
set %1=%2
)
exit /b
Я знаю, что опаздываю в клуб, и это не обязательно ответ, но я хотел бы добавить одну вещь, которая могла бы помочь прояснить немного. Я всегда думал о передаче имени Algol как процесс, подобный тому, когда директивы препроцессора C++ (в частности, макросы) заменяют имя некоторой функции / переменной на фактический кусок кода во время компиляции. Передача по имени по существу заменяет имя формального параметра фактическим параметром и выполняется. Я никогда не писал на Алголе, но я слышал, что передача по имени будет иметь тот же результат, что и передача по С ++.
Вы можете передать "имя" в символической форме переменной, которая позволяет одновременно обновлять и получать к ней доступ. В качестве примера предположим, что вы хотите утроить переменную x типа int:
start double(x);
real x;
begin
x : = x * 3
end;
Flatlander имеет яркий пример того, как он работает в Scala здесь. Предположим, вы хотели реализовать пока:
def mywhile(condition: => Boolean)(body: => Unit): Unit = if (condition) { body mywhile(condition)(body) }
Мы можем назвать это следующим образом:
var i = 0 mywhile (i < 10) { println(i) i += 1 }
Scala - это не Algol 60, но, возможно, он проливает свет.
ALGOL был разработан для математических алгоритмов. Мне нравится функция суммирования в качестве примера вызова по имени.
Извините, мой Алгол немного ржавый, синтаксис, вероятно, не правильный.
.FUNCTION SUM(var,from,to,function)
.BEGIN
.REAL sum =0;
.FOR var = from .TO to .DO sum = function;
return sum;
.END
Вы могли бы, чем использовать сумму, как
Y = sum(x,1,4,sum(y,3,8,x+y));
В приведенном выше примере внутренняя сумма (y,3,8,x+y) генерирует безымянную функцию для передачи на вызов внешней суммы. Переменные x и y передаются не по значению, а по имени. В случае переменных вызов по имени эквивалентен вызову по ссылке на адрес в Си. При использовании рекурсии это немного сбивает с толку.
Занимается изготовлением машин ALGOL. У них была 48-битная память слов с 3 флагами. Биты флага реализовали вызов по имени ALGOL. это была машина стека, поэтому, когда функция загружалась в стек, вызов по имени fag вызывал ее вызов. Компилятор генерирует безымянные функции, когда выражения используются в качестве аргументов. Переменная будет простой косвенной ссылкой. Произошла ошибка при записи в функцию.
Обратите внимание, что «вызов по имени» считался проблематичным на практике и поэтому не копировался в дизайн языка Pascal, который в остальном сильно заимствован из Algol.