Стратегия оценки
Стратегии оценки |
---|
В языке программирования стратегия вычисления — это набор правил вычисления выражений. [1] Этот термин часто используется для обозначения более конкретного понятия стратегии передачи параметров. [2] который определяет тип значения, передаваемого функции для каждого параметра ( стратегия привязки ) [3] и следует ли оценивать параметры вызова функции, и если да, то в каком порядке ( порядок оценки ). [4] Понятие стратегии сокращения является четким, [5] хотя некоторые авторы объединяют эти два термина, и определение каждого термина не получило широкого согласия. [6]
Чтобы проиллюстрировать, выполнение вызова функции f(a,b)
может сначала оценить аргументы a
и b
, сохранять результаты в ссылках или ячейках памяти ref_a
и ref_b
, затем оцените тело функции с переданными ссылками. Это дает функции возможность искать исходные значения аргументов, переданных путем разыменования параметров (некоторые языки используют для этого специальные операторы), чтобы изменять их посредством присваивания, как если бы они были локальными переменными и возвращали значения через ссылки. Это стратегия оценки по ссылке. [7]
Стратегия оценки является частью семантики определения языка программирования. Некоторые языки, такие как PureScript , имеют варианты с разными стратегиями оценки. Некоторые декларативные языки , такие как Datalog , поддерживают несколько стратегий оценки. Некоторые языки определяют соглашение о вызовах . [ нужны разъяснения ]
Стол
[ редактировать ]Это таблица стратегий оценки и репрезентативных языков по годам введения. Репрезентативные языки перечислены в хронологическом порядке, начиная с языка(ов), на которых была представлена стратегия, и заканчивая известными языками, использующими эту стратегию. [8] : 434
Стратегия оценки | Репрезентативные языки | Год первого представления |
---|---|---|
Звонок по ссылке | Фортран II, PL/I | 1958 |
Вызов по значению | АЛГОЛ , C , Схема , MATLAB [9] | 1960 |
Звонок по имени | АЛГОЛ 60 , Моделирование | 1960 |
Звонок путем копирования-восстановления | Фортран IV , Да [10] | 1962 |
Звонок по объединению | Пролог | 1965 [11] [12] |
Звонок по необходимости | САСЛ , [13] Хаскелл , Р. [14] | 1971 [15] |
Позвоните, поделившись | CLU , Java , Python , Руби , Джулия | 1974 [16] |
Вызов по ссылочным параметрам | С++ , PHP , [17] С# , [18] Визуальный Бейсик .NET [19] | 1985 [20] |
Вызов по ссылке на const | С++ , С | 1985 [20] |
Заказы на оценку
[ редактировать ]Хотя порядок операций определяет абстрактное синтаксическое дерево выражения, порядок вычисления определяет порядок, в котором вычисляются выражения. Например, программа Python
def f(x):
print(x, end='')
return x
print(f(1) + f(2),end='')
результаты 123
из-за порядка вычислений Python слева направо, но аналогичная программа в OCaml :
let f x = print_int x; x ;;
print_int (f 1 + f 2)
результаты 213
из-за порядка вычислений OCaml справа налево.
Порядок вычислений в основном виден в коде с побочными эффектами , но он также влияет на производительность кода, поскольку жесткий порядок препятствует планированию инструкций . По этой причине языковые стандарты, такие как C++, традиционно оставляют порядок неопределенным, хотя такие языки, как Java и C#, определяют порядок вычислений слева направо. [8] : 240–241 а стандарт C++17 добавил ограничения на порядок вычислений. [21]
Строгая оценка
[ редактировать ]Аппликативный порядок — это семейство порядков вычислений, в которых аргументы функции полностью оцениваются перед применением функции. [22] Это приводит к тому, что функция становится строгой , т. е. результат функции не определен, если какой-либо из аргументов не определен, поэтому оценку аппликативного порядка чаще называют строгой оценкой . Более того, вызов функции выполняется, как только он встречается в процедуре, поэтому его также называют нетерпеливой оценкой или жадной оценкой . [23] [24] Некоторые авторы называют строгую оценку «вызовом по значению» из-за стратегии привязки вызова по значению, требующей строгой оценки. [4]
Common Lisp, Eiffel и Java оценивают аргументы функции слева направо. C оставляет порядок неопределенным. [25] Схема требует, чтобы порядок выполнения представлял собой последовательное выполнение неопределенной перестановки аргументов. [26] OCaml аналогичным образом оставляет порядок неопределенным, но на практике аргументы оцениваются справа налево из-за конструкции своей абстрактной машины . [27] Все это строгая оценка.
Нестрогая оценка
[ редактировать ]Нестрогий порядок вычисления — это нестрогий порядок вычисления, то есть функция может вернуть результат до того, как все ее аргументы будут полностью оценены. [28] : 46–47 Прототипическим примером является оценка обычного порядка , которая не оценивает ни один из аргументов, пока они не потребуются в теле функции. [29] Вычисление обычного порядка имеет то свойство, что оно завершается без ошибок всякий раз, когда любой другой порядок вычисления завершился бы без ошибок. [30] Название «нормальный порядок» происходит от лямбда-исчисления, где приведение нормального порядка находит нормальную форму, если таковая имеется (это «нормализующая» стратегия приведения ). [31] В этой статье ленивая оценка классифицируется как метод привязки, а не как порядок оценки. Но это различие не всегда соблюдается, и некоторые авторы определяют ленивую оценку как оценку в обычном порядке или наоборот. [22] [32] или путайте нестрогость с ленивой оценкой. [28] : 43–44
Во многих языках логические выражения используют форму нестрогого вычисления, называемую сокращенным вычислением , при котором вычисление оценивает левое выражение, но может пропустить правое выражение, если результат может быть определен — например, в дизъюнктивном выражении (ИЛИ), где true
встречается или в союзном выражении (И), где false
встречается и так далее. [32] В условных выражениях аналогично используется нестрогое вычисление — оценивается только одна из ветвей. [28]
Сравнение аппликативного порядка и оценки нормального порядка
[ редактировать ]При обычном вычислении порядка выражения, содержащие дорогостоящие вычисления, ошибки или бесконечный цикл, будут игнорироваться, если они не нужны. [4] позволяющая специфицировать определяемые пользователем конструкции потока управления, возможность, недоступная при аппликативной оценке порядка. При обычной оценке порядка используются сложные структуры, такие как преобразователи для невычисленных выражений, по сравнению со стеком вызовов, используемым при аппликативной оценке порядка. [33] При обычной оценке порядка исторически не хватало полезных инструментов отладки из-за ее сложности. [34]
Стратегии строгого связывания
[ редактировать ]Вызов по значению
[ редактировать ]При вызове по значению (или передаче по значению) вычисленное значение выражения аргумента привязывается к соответствующей переменной в функции (часто путем копирования значения в новую область памяти). Если функция или процедура могут присваивать значения своим параметрам, присваивается только ее локальная переменная, т. е. все, что передается в вызов функции, остается неизменным в области вызывающего объекта при возвращении функции. Например, в Pascal передача массива по значению приведет к копированию всего массива, и любые изменения в этом массиве будут невидимы для вызывающей стороны: [35]
program Main;
uses crt;
procedure PrintArray(a: Array of integer);
var
i: Integer;
begin
for i := Low(a) to High(a) do
Write(a[i]);
WriteLn();
end;
Procedure Modify(Row : Array of integer);
begin
PrintArray(Row); // 123
Row[1] := 4;
PrintArray(Row); // 143
end;
Var
A : Array of integer;
begin
A := [1,2,3];
PrintArray(A); // 123
Modify(A);
PrintArray(A); // 123
end.
Семантический дрейф
[ редактировать ]Строго говоря, при вызове по значению никакие операции, выполняемые вызываемой подпрограммой, не могут быть видны вызывающей стороне, кроме как как часть возвращаемого значения. [16] Это подразумевает форму чисто функционального программирования в семантике реализации. Однако оборот «вызов по значению, где значение является ссылкой» стал обычным явлением, например, в сообществе Java. [36] По сравнению с традиционной передачей по значению, передаваемое значение — это не значение в его обычном значении, например целое число, которое можно записать как литерал, а внутренний дескриптор ссылки реализации . Изменения этого дескриптора ссылки видны в вызывающем объекте. Из-за видимой мутации эту форму «вызова по значению» правильнее называть вызовом путем совместного использования . [16]
В чисто функциональных языках значения и структуры данных неизменяемы, поэтому у функции нет возможности изменить какой-либо из своих аргументов. Таким образом, обычно нет семантической разницы между передачей по значению и передачей по ссылке или указателю на структуру данных, и реализации часто используют внутренний вызов по ссылке для повышения эффективности. Тем не менее, эти языки обычно описываются как языки вызова по значению.
Звонок по ссылке
[ редактировать ]Вызов по ссылке (или передача по ссылке) — это стратегия оценки, при которой параметр привязывается к неявной ссылке на переменную, используемую в качестве аргумента, а не к копии ее значения. Обычно это означает, что функция может изменять (т. е. присваивать ) переменную, используемую в качестве аргумента, — то, что будет видно вызывающей стороне. Таким образом, вызов по ссылке может использоваться для предоставления дополнительного канала связи между вызываемой функцией и вызывающей функцией. Передача по ссылке может значительно повысить производительность: вызов функции с многомегабайтной структурой в качестве аргумента не требует копирования большой структуры, а только ссылки на структуру (которая обычно представляет собой машинное слово и занимает всего несколько байт). Однако язык вызова по ссылке затрудняет программисту отслеживание последствий вызова функции и может привести к появлению мелких ошибок.
Из-за различий в синтаксисе разница между вызовом по ссылке (где ссылочный тип является неявным) и вызовом путем совместного использования (где ссылочный тип является явным) на первый взгляд часто неясна. Простой лакмусовой бумажкой является возможность написать традиционный swap(a, b)
функционировать в языке. [36] Например, на Фортране:
program Main
implicit none
integer :: a = 1
integer :: b = 2
call Swap(a, b)
print *, a, b ! 2 1
contains
subroutine Swap(a, b)
integer, intent(inout) :: a, b
integer :: temp
temp = a
a = b
b = temp
end subroutine Swap
end program Main
Таким образом, Фортран inout
намерение реализует вызов по ссылке; любая переменная может быть неявно преобразована в ссылочный дескриптор. Напротив, самое близкое, что можно получить в Java:
class Main {
static class Box {
int value;
public Box(int value) {
this.value = value;
}
}
static void swap(Box a, Box b) {
int temp = a.value;
a.value = b.value;
b.value = temp;
}
public static void main(String[] args) {
Box a = new Box(1);
Box b = new Box(2);
swap(a, b);
System.out.println(String.format("%d %d", a.value, b.value));
}
}
// output: 2 1
где явное Box
type должен использоваться для введения дескриптора. Java использует вызов путем совместного использования, но не вызов по ссылке. [36]
Звонок путем копирования-восстановления
[ редактировать ]Вызов путем копирования-восстановления, также известный как «копирование-вход-выход», «вызов по результату значения», «вызов по возврату значения» (как это называется в сообществе Fortran ) — это вариант вызова по ссылке. При вызове методом копирования-восстановления содержимое аргумента копируется в новую переменную, локальную для вызова вызова. Затем функция может изменить эту переменную, аналогично вызову по ссылке, но поскольку переменная является локальной, изменения не видны за пределами вызова во время вызова. Когда вызов функции возвращает значение, обновленное содержимое этой переменной копируется обратно, чтобы перезаписать исходный аргумент («восстановлено»). [37]
Семантика вызова путем копирования-восстановления во многих случаях аналогична вызову по ссылке, но отличается, когда два или более аргумента функции псевдонимируют друг друга (т. е. указывают на одну и ту же переменную в среде вызывающего объекта). При вызове по ссылке запись в один аргумент повлияет на другой во время выполнения функции. При вызове путем копирования-восстановления запись в один аргумент не повлияет на другой во время выполнения функции, но в конце вызова значения двух аргументов могут отличаться, и неясно, какой аргумент копируется первым и, следовательно, какое значение получает переменная вызывающего объекта. [38] Например, Ада определяет, что назначение копирования для каждого in out
или out
параметр встречается в произвольном порядке. [39] Из следующей программы (незаконно в Ada 2012) [40] видно, что поведение GNAT заключается в копировании в порядке слева направо:
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Copy_Restore is
procedure Modify (A, B : in out Integer) is
begin
A := A + 1;
B := B + 2;
end Modify;
X : Integer := 0;
begin
Modify(X, X);
Put_Line("X = " & Integer'Image(X));
end Test_Copy_Restore;
-- $ gnatmake -gnatd.E test_copy_restore.adb; ./test_copy_restore
-- test_copy_restore.adb:12:10: warning: writable actual for "A" overlaps with actual for "B" [-gnatw.i]
-- X = 2
Если бы программа вернула 1, она бы копировала справа налево, а при вызове по семантике ссылки программа вернула бы 3.
Когда ссылка передается вызывающей стороне неинициализированной (например, out
параметр в Ada в отличие от in out
параметр), эту стратегию оценки можно назвать «вызов по результату».
Эта стратегия привлекла внимание при многопроцессорной обработке и удаленных вызовах процедур . [41] поскольку в отличие от вызова по ссылке он не требует частого взаимодействия между потоками выполнения для доступа к переменным.
Позвоните, поделившись
[ редактировать ]Вызов путем совместного использования (также известный как «передача путем совместного использования», «вызов по объекту» или «вызов путем совместного использования объекта») — это стратегия оценки, которая является промежуточной между вызовом по значению и вызовом по ссылке. Вместо того, чтобы каждая переменная представлялась как ссылка, только определенный класс значений, называемый «ссылками», « коробочными типами » или «объектами», имеет ссылочную семантику, и именно адреса этих указателей передаются в функцию. . Как и вызов по значению, значение переданного адреса является копией, а прямое присвоение параметру функции перезаписывает копию и не отображается для вызывающей функции. Как и вызов по ссылке, изменение цели указателя видно вызывающей функции. Мутации изменяемого объекта внутри функции видны вызывающей стороне, поскольку объект не копируется и не клонируется — он является общим , отсюда и название «вызов путем совместного использования». [16]
Впервые этот метод был описан Барбарой Лисковой в 1974 году для языка CLU . [16] Он используется во многих современных языках, таких как Python (общие значения называются «объектами»), [42] Java (объекты), Ruby (объекты), JavaScript (объекты), Scheme (структуры данных, такие как векторы), [43] AppleScript (списки, записи, даты и объекты сценариев), OCaml и ML (ссылки, записи, массивы, объекты и другие составные типы данных), Maple (таблицы и таблицы) и Tcl (объекты). [44] Термин «вызов путем совместного использования», используемый в этой статье, не широко используется; терминология противоречива в разных источниках. Например, в Java-сообществе говорят, что Java — это вызов по значению. [36]
Для неизменяемых объектов нет реальной разницы между вызовом путем совместного использования и вызовом по значению, за исключением случаев, когда идентификатор объекта виден в языке. Использование вызова путем совместного использования с изменяемыми объектами является альтернативой параметрам ввода/вывода : параметр не назначается (аргумент не перезаписывается и идентификатор объекта не изменяется), но объект (аргумент) мутируется. [45]
Например, в Python списки изменяемы и передаются при вызове путем совместного использования, поэтому:
def f(a_list):
a_list.append(1)
m = []
f(m)
print(m)
результаты [1]
потому что append
Метод изменяет объект, для которого он вызывается.
Напротив, присвоения внутри функции не заметны для вызывающей стороны. Например, этот код привязывает формальный аргумент к новому объекту, но он не виден вызывающей стороне, поскольку не изменяется. a_list
:
def f(a_list):
a_list = a_list + [1]
print(a_list) # [1]
m = []
f(m)
print(m) # []
Звонок по адресу
[ редактировать ]Вызов по адресу , передача по адресу или вызов/передача по указателю — это метод передачи параметра, при котором адрес аргумента передается как формальный параметр. Внутри функции адрес (указатель) может использоваться для доступа или изменения значения аргумента. Например, операция замены может быть реализована в C следующим образом: [46]
#include <stdio.h>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 1;
int b = 2;
swap(&a, &b);
printf("%d %d", a, b); // 2 1
return 0;
}
Некоторые авторы рассматривают &
как часть синтаксиса вызова swap
. С этой точки зрения C поддерживает стратегию передачи параметров по ссылке. [47] Другие авторы придерживаются иной точки зрения, что представленная реализация swap
в C — это всего лишь симуляция вызова по ссылке с использованием указателей. [48] С этой точки зрения «симуляции» изменяемые переменные в C не являются первоклассными (то есть l-значения не являются выражениями), а типы указателей. С этой точки зрения представленная программа подкачки является синтаксическим сахаром для программы, которая повсюду использует указатели. [49] например эта программа( read
и assign
были добавлены, чтобы подчеркнуть сходство с Java Box
программа совместного вызова выше ):
#include <stdio.h>
int read(int *p) {
return *p;
}
void assign(int *p, int v) {
*p = v;
}
void swap(int* a, int* b) {
int temp_storage; int* temp = &temp_storage;
assign(temp, read(a));
assign(a, read(b));
assign(b, read(temp));
}
int main() {
int a_storage; int* a = &a_storage;
int b_storage; int* b = &b_storage;
assign(a,1);
assign(b,2);
swap(a, b);
printf("%d %d", read(a), read(b)); // 2 1
return 0;
}
Потому что в этой программе swap
работает с указателями и не может изменять сами указатели, а только те значения, на которые указывают указатели. Эта точка зрения предполагает, что основная стратегия оценки C больше похожа на совместное использование вызова.
C++ еще больше запутывает проблему, позволяя swap
должен быть объявлен и использован с очень легким «эталонным» синтаксисом: [50]
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1;
int b = 2;
swap(a, b);
std::cout << a << b << std::endl; // 2 1
return 0;
}
Семантически это эквивалентно примерам на C. Таким образом, многие авторы считают вызов по адресу уникальной стратегией передачи параметров, отличной от вызова по значению, вызова по ссылке и совместного использования.
Звонок по объединению
[ редактировать ]В логическом программировании вычисление выражения может просто соответствовать унификации задействованных терминов в сочетании с применением некоторой формы разрешения . Унификацию следует классифицировать как стратегию строгого связывания, поскольку она полностью реализована. Однако унификация также может быть выполнена для неограниченных переменных, поэтому вызовы не обязательно могут фиксировать окончательные значения для всех переменных.
Стратегии нестрогого связывания
[ редактировать ]Звонок по имени
[ редактировать ]Вызов по имени — это стратегия оценки, при которой аргументы функции не оцениваются до вызова функции — скорее, они подставляются непосредственно в тело функции (с использованием подстановки, избегающей захвата ), а затем оставляются для оценки всякий раз, когда они появляются в функция. Если аргумент не используется в теле функции, он никогда не оценивается; если он используется несколько раз, он пересчитывается каждый раз, когда появляется. ( см. в устройстве Дженсена Технику программирования, которая использует это, .)
Оценка вызова по имени иногда предпочтительнее оценки вызова по значению. Если аргумент функции не используется в функции, вызов по имени сэкономит время, не оценивая аргумент, тогда как вызов по значению все равно оценит его. Если аргумент представляет собой непрерывные вычисления, преимущество огромно. Однако, когда используется аргумент функции, вызов по имени часто происходит медленнее и требует такого механизма, как thunk .
Языки .NET могут имитировать вызов по имени с помощью делегатов или Expression<T>
параметры. Последнее приводит к тому, что абстрактное синтаксическое дерево функции передается . Eiffel предоставляет агенты, которые представляют собой операцию, которую необходимо оценить при необходимости. Seed7 обеспечивает вызов по имени с параметрами функции. Программы Java могут выполнять аналогичные ленивые вычисления, используя лямбда-выражения и java.util.function.Supplier<T>
интерфейс.
Звонок по необходимости
[ редактировать ]Вызов по необходимости — это запоминаемый вариант вызова по имени, где, если аргумент функции оценивается, это значение сохраняется для последующего использования. Если аргумент является чистым (т. е. не имеет побочных эффектов), это дает те же результаты, что и вызов по имени, экономя затраты на повторное вычисление аргумента.
Haskell — хорошо известный язык, использующий оценку по мере необходимости. Поскольку вычисление выражений может происходить на произвольной стадии вычисления, Haskell поддерживает только побочные эффекты (такие как мутации ) посредством использования монад . Это исключает любое неожиданное поведение переменных, значения которых изменяются до их отложенной оценки.
В реализации вызова по необходимости в R передаются все аргументы, а это означает, что R допускает произвольные побочные эффекты.
Ленивая оценка — это наиболее распространенная реализация семантики вызова по необходимости, но существуют ее варианты, такие как оптимистическая оценка . Языки .NET реализуют вызов по необходимости, используя тип Lazy<T>
.
Сокращение графа — это эффективная реализация ленивых вычислений.
Вызов с помощью расширения макроса
[ редактировать ]Вызов по раскрытию макроса аналогичен вызову по имени, но использует текстовую замену, а не замену без захвата . Таким образом, макрозамена может привести к захвату переменных, что приведет к ошибкам и нежелательному поведению. Гигиенические макросы позволяют избежать этой проблемы, проверяя и заменяя затененные переменные , которые не являются параметрами.
Звонок в будущее
[ редактировать ]«Звонок по будущему», также известный как «параллельный вызов по имени» или «снисходительная оценка», [51] — это стратегия параллельной оценки, сочетающая нестрогую семантику с нетерпеливой оценкой. Этот метод требует детального динамического планирования и синхронизации, но подходит для машин с массовым параллелизмом.
Стратегия создает будущее (обещание) для тела функции и каждого из ее аргументов. Эти фьючерсы вычисляются одновременно с остальной частью программы. Когда фьючерсу A требуется значение другого фьючерса B, которое еще не было вычислено, фьючерс A блокируется до тех пор, пока фьючерс B не завершит вычисление и не обретет значение. Если будущий B уже завершил вычисления, значение возвращается немедленно. Условные выражения блокируются до тех пор, пока их условие не будет оценено, а лямбда-выражения не создают фьючерсы до тех пор, пока они не будут полностью применены. [52]
Если оно реализовано с помощью процессов или потоков, создание будущего порождает один или несколько новых процессов или потоков (для промисов), доступ к значению синхронизирует их с основным потоком, а прекращение вычисления будущего соответствует уничтожению промисов, вычисляющих его. ценить. Если реализовано с помощью сопрограммы , как в .NET async/await , создание будущего вызывает сопрограмму (асинхронную функцию), которая может передаваться вызывающему объекту и, в свою очередь, возвращаться обратно при использовании значения, обеспечивая совместную многозадачность.
Стратегия является недетерминированной, поскольку оценка может происходить в любой момент между созданием будущего (т. е. когда задано выражение) и использованием значения будущего. Стратегия не является строгой, поскольку тело функции может возвращать значение до того, как будут вычислены аргументы. Однако в большинстве реализаций выполнение все равно может зависнуть при оценке ненужного аргумента. Например, программа
f x = 1/x
g y = 1
main = print (g (f 0))
может иметь g
закончить раньше f
и выход 1, или может привести к ошибке из-за вычисления 1/0
. [28]
Вызов по будущему аналогичен вызову по необходимости в том, что значения вычисляются только один раз. При тщательной обработке ошибок и незавершений, в частности, при прерывании фьючерсов на полпути, если определено, что они не понадобятся, вызов по будущему также имеет те же свойства завершения, что и оценка вызова по необходимости. [52] Однако вызов по будущему может выполнять ненужную спекулятивную работу по сравнению с вызовом по необходимости, например глубокую оценку ленивой структуры данных. [28] Этого можно избежать, используя ленивые фьючерсы, которые не начинают вычисления до тех пор, пока не будет уверенности, что значение необходимо.
Оптимистическая оценка
[ редактировать ]Оптимистическая оценка — это вариант вызова по необходимости, при котором аргумент функции частично оценивается в стиле вызова по значению в течение некоторого времени (которое может быть скорректировано во время выполнения ). По истечении этого времени вычисление прерывается и функция применяется с использованием вызова по необходимости. [53] Этот подход позволяет избежать некоторых затрат времени выполнения вызова по необходимости, сохраняя при этом желаемые характеристики завершения.
См. также
[ редактировать ]- Бета-нормальная форма
- Сравнение языков программирования
- оценивать
- Лямбда-исчисление
- Вызов по значению push
- Частичная оценка
Ссылки
[ редактировать ]Эта статья включает список общих ссылок , но в ней отсутствуют достаточные соответствующие встроенные цитаты . ( Апрель 2012 г. ) |
- ^ Араки, Шота; Нисидзаки, Син-я (ноябрь 2014 г.). «Оценка исчислений RPC и RMI по имени». Теория и практика вычислений . п. 1. дои : 10.1142/9789814612883_0001 . ISBN 978-981-4612-87-6 . Проверено 21 августа 2021 г.
- ^ Турбак, Франклин; Гиффорд, Дэвид (18 июля 2008 г.). Концепции проектирования в языках программирования . МТИ Пресс. п. 309. ИСБН 978-0-262-30315-6 .
- ^ Кранк, Эрик; Феллейзен, Матиас (1991). «Передача параметров и лямбда-исчисление». Материалы 18-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования — POPL '91 . п. 2. CiteSeerX 10.1.1.23.4385 . дои : 10.1145/99583.99616 . ISBN 0897914198 . S2CID 5782416 .
- ^ Перейти обратно: а б с Вильгельм, Рейнхард; Зайдль, Гельмут (10 ноября 2010 г.). Проектирование компилятора: виртуальные машины . Springer Science & Business Media. п. 61. ИСБН 978-3-642-14909-2 .
- ^ Нита, Стефания Лоредана; Михайлеску, Мариус (2017). "Введение" . Практический параллельный Haskell . стр. 3. два : 10.1007/978-1-4842-2781-7_1 . ISBN 978-1-4842-2780-0 .
- ^ Пирс, Бенджамин К. (2002). Типы и языки программирования . МТИ Пресс . п. 56. ИСБН 0-262-16209-1 .
- ^ Дэниел П. Фридман; Митчелл Ванд (2008). Основы языков программирования (третье изд.). Кембридж, Массачусетс: MIT Press . ISBN 978-0262062794 .
- ^ Перейти обратно: а б Скотт, Майкл Ли (2016). Прагматика языка программирования (Четвертое изд.). Уолтем, Массачусетс: Эльзевир. ISBN 9780124104778 .
- ^ «Избегайте ненужных копий данных — MATLAB & Simulink» . www.mathworks.com . Проверено 28 января 2023 г.
- ^ Хасти, Ребекка. «Передача параметров» . CS 536: Введение в языки программирования и компиляторы . Университет Висконсина . Проверено 22 августа 2021 г.
- ^ Дж. А. Робинсон (январь 1965 г.). «Машинно-ориентированная логика, основанная на принципе разрешения» . Журнал АКМ . 12 (1): 23–41. дои : 10.1145/321250.321253 . S2CID 14389185 . ; Здесь: разд.5.8, стр.32
- ^ Дж. А. Робинсон (1971). «Вычислительная логика: унификация вычислений» . Машинный интеллект . 6 : 63–72.
- ^ Банди, Алан; Валлен, Линкольн (1984). «САСЛ». Каталог инструментов искусственного интеллекта . п. 117. дои : 10.1007/978-3-642-96868-6_222 . ISBN 978-3-540-13938-6 .
Вероятно, это был первый язык, который систематически использовал возможности ленивых вычислений.
- ^ Фэй, Колин (30 июля 2018 г.). «О ленивой оценке» . R-блогеры . Проверено 21 августа 2021 г.
- ^ Уодсворт, Кристофер П. (1971). Семантика и прагматика лямбда-исчисления (доктор философии). Оксфордский университет.
- ^ Перейти обратно: а б с д и Лисков, Варвара; Аткинсон, Расс; Блум, Тоби; Мосс, Элиот; Шафферт, Крейг; Шайфлер, Крейг; Снайдер, Алан (октябрь 1979 г.). «Справочное руководство CLU» (PDF) . Лаборатория компьютерных наук . Массачусетский технологический институт. стр. 14–15. Архивировано (PDF) из оригинала 22 сентября 2006 г. Проверено 19 мая 2011 г.
- ^ «PHP: Передача по ссылке — Руководство» . www.php.net . Проверено 4 июля 2021 г.
- ^ Вагнер, Билл (12 апреля 2023 г.). «Передача параметров — Руководство по программированию на C#» . Документы Майкрософт . Проверено 10 сентября 2023 г.
- ^ Доллард, Кэтлин (15 сентября 2021 г.). «Передача аргументов по значению и по ссылке — Visual Basic» . Документы Майкрософт . Проверено 10 сентября 2023 г.
- ^ Перейти обратно: а б «История С++» . ru.cppreference.com . Проверено 11 июня 2022 г.
- ^ Филипек, Бартломей (16 августа 2021 г.). «Строгий порядок вычисления выражений в C++17» . Истории С++ . Проверено 24 августа 2021 г.
- ^ Перейти обратно: а б Абельсон, Гарольд ; Сассман, Джеральд Джей (1996). «Нормальный порядок и аппликативный порядок» . Структура и интерпретация компьютерных программ (2-е изд.). Кембридж, Массачусетс: MIT Press . ISBN 0-262-01153-0 . Архивировано из оригинала 02 марта 2005 г. Проверено 6 марта 2006 г. См. также сноску Temp 576.
- ^ Риз, Ричард М. (14 октября 2015 г.). Изучение функционального программирования на Java . Packt Publishing Ltd. с. 106. ИСБН 978-1-78528-935-4 .
- ^ Антани, Вед; Тиммс, Саймон; Мантила, Дэн (31 августа 2016 г.). JavaScript: функциональное программирование для разработчиков JavaScript . Packt Publishing Ltd. с. 614. ИСБН 978-1-78712-557-5 .
- ^ Сикорд, Роберт С. «EXP30-C. Не зависит от порядка оценки побочных эффектов» . SEI CERT Стандарт кодирования C. Университет Карнеги-Меллон . Проверено 23 августа 2021 г.
- ^ Англаде, С.; Лакрамп, Джей Джей; Кейннек, К. (октябрь 1994 г.). «Семантика сочетаний в схеме» (PDF) . Указатели Lisp ACM SIGPLAN . VII (4): 15–20. дои : 10.1145/382109.382669 . S2CID 2987427 .
- ^ «Почему аргументы функции OCaml оцениваются справа налево?» . ОКамл . 30 ноября 2017 г.
- ^ Перейти обратно: а б с д и Трамбле, Г. (апрель 2000 г.). «Снисходительная оценка не является ни строгой, ни ленивой». Компьютерные языки . 26 (1): 43–66. CiteSeerX 10.1.1.137.9885 . дои : 10.1016/S0096-0551(01)00006-6 .
- ^ Джордж, Лай (март 1987 г.). Эффективная оценка нормального порядка посредством информации о строгости (MSc). Университет Юты. п. 10.
- ^ Борнинг, Алан (осень 1999 г.). «Аппликация против оценки нормального порядка в функциональных языках» (PDF) . CSE 505: Концепции языков программирования . Университет Вашингтона . Проверено 23 августа 2021 г.
- ^ Маццола, Гуэрино; Мильмейстер, Жерар; Вайсманн, Джоди (21 октября 2004 г.). Комплексная математика для компьютерщиков 2 . Springer Science & Business Media. п. 323. ИСБН 978-3-540-20861-7 .
- ^ Перейти обратно: а б Штурм, Оливер (11 апреля 2011 г.). Функциональное программирование на C#: классические методы программирования для современных проектов . Джон Уайли и сыновья. п. 91. ИСБН 978-0-470-74458-1 .
- ^ Марлоу, Саймон. «Почему я не могу получить трассировку стека?» . Семинар разработчиков Haskell 2012 . Проверено 25 августа 2021 г.
- ^ Нильссон, Хенрик (1999). «Трассировка по частям: доступная отладка для ленивых функциональных языков». Материалы четвертой международной конференции ACM SIGPLAN по функциональному программированию . стр. 36–47. CiteSeerX 10.1.1.451.6513 . дои : 10.1145/317636.317782 . ISBN 1581131119 . S2CID 13954359 .
- ^ «Параметры открытого массива» . www.freepascal.org . Проверено 20 января 2024 г.
- ^ Перейти обратно: а б с д «Java — это передача по значению, черт возьми!» . 16 мая 2001 года . Проверено 24 декабря 2016 г.
- ^ Коэнен, Франс. «СООТВЕТСТВИЕ ПАРАМЕТРА» . cgi.csc.liv.ac.uk. Проверено 22 января 2024 г.
- ^ «Вызов по ссылке, проблемы с псевдонимами» (PDF) . Курс MPRI 2-36-1: Проверка программы (конспекты лекций) . п. 53.
- ^ Справочное руководство по языку Ada 2022 (PDF) , 13 октября 2023 г., стр. 215
- ^ Барнс, Джон (2013). Обоснование Ada 2012: язык, стандартные библиотеки (PDF) . Гейдельберг: Спрингер. п. 15-16,87-88. ISBN 978-3-642-45210-9 .
- ^ Терлоу, Роберт (май 2009 г.). «RPC: Спецификация протокола удаленного вызова процедур, версия 2» . www.tools.ietf.org . IETF . Проверено 7 апреля 2018 г.
- ^ Лунд, Фредрик. «Вызов по объекту» . Effbot.org . Архивировано из оригинала 19 мая 2011 г. Проверено 19 мая 2011 г.
- ^ Джонс, Рис Прайс (2010). «Вызов Scheme по значению?» . CS 145 Языки программирования. Лабораторная работа 9: Передача параметров . Университет Джорджа Вашингтона. Архивировано из оригинала 16 октября 2014 года . Проверено 20 января 2024 г.
- ^ «Процедуры библиотеки Tcl — страница руководства Tcl_Obj» . www.tcl.tk.
- ^ «CA1021: Избегайте выходных параметров» . Майкрософт. 15 ноября 2016 г.
- ^ Лео, Рэй (ноябрь 1996 г.). Маленький C++ (сделано проще) . LeoSudo Inc., стр. 79–80. ISBN 978-0-9654634-1-6 .
- ^ Дандамуди, Шиварама П. (15 июля 2005 г.). Руководство по программированию на языке ассемблера в Linux . Springer Science & Business Media. п. 232. ИСБН 978-0-387-25897-3 .
- ^ Шривастава, СК; Шривастава, Дипали (6 июня 2018 г.). C в глубине . Публикации БПБ. п. 206. ИСБН 978-93-87284-94-4 .
- ^ «Изменяемые переменные и ссылочные типы» . okmij.org . Проверено 20 января 2024 г.
- ^ Вермейр, Дирк (28 июня 2011 г.). Мультипарадигмальное программирование с использованием C++ . Springer Science & Business Media. стр. 10–11. ISBN 978-1-4471-0311-0 .
- ^ МакКоллин, Томас Гвинфрин; Морелл, Тобиас. «Игра парадигм: исследование удобства использования функциональных идиом в программировании игрового процесса» (PDF) . Ольборгский университет. п. 6 . Проверено 11 января 2022 г.
- ^ Перейти обратно: а б Шаузер, Клаус Э.; Гольдштейн, Сет К. (1995). «Какой степени нестрогости требуют мягкие программы?» (PDF) . Материалы седьмой международной конференции «Функциональные языки программирования и компьютерная архитектура — FPCA '95» . стр. 216–225. дои : 10.1145/224164.224208 . ISBN 0897917197 . S2CID 2045943 . Проверено 7 января 2022 г.
- ^ Энналс, Роберт; Джонс, Саймон Пейтон (август 2003 г.). «Оптимистическая оценка: стратегия быстрой оценки для нестрогих программ» .
Дальнейшее чтение
[ редактировать ]- Бейкер-Финч, Клем; Король, Дэвид; Холл, Джон; Триндер, Фил (10 марта 1999 г.). «Операционная семантика для параллельного вызова по необходимости» (ps) . Отчет об исследовании . 99 (1). Факультет математики и информатики Открытого университета.
- Энналс, Роберт; Пейтон Джонс, Саймон (2003). Оптимистическая оценка: стратегия быстрой оценки нестрогих программ (PDF) . Международная конференция по функциональному программированию. АКМ Пресс.
- Людешер, Бертрам (24 января 2001 г.). «Конспекты лекций CSE 130» . CSE 130: Языки программирования: принципы и парадигмы .
- Пирс, Бенджамин К. (2002). Типы и языки программирования . МТИ Пресс . ISBN 0-262-16209-1 .
- Сестофт, Питер (2002). Могенсен, Т; Шмидт, Д; Садборо, Айдахо (ред.). Демонстрация сокращения лямбда-исчисления (PDF) . Конспекты лекций по информатике. Том. 2566. Шпрингер-Верлаг. стр. 420–435. ISBN 3-540-00326-6 .
{{cite book}}
:|work=
игнорируется ( помогите ) - «Вызов по значению и вызов по ссылке в программировании на C» . Объяснение вызова по значению и вызову по ссылке в программировании на C. Архивировано из оригинала 21 января 2013 г.
Внешние ссылки
[ редактировать ]- Интерактивный онлайн- «Геометрия взаимодействия» визуализатор , реализующий графическую машину для нескольких распространенных стратегий оценки.