stringtranslate.com

Стратегия оценки

В языке программирования стратегия вычисления — это набор правил вычисления выражений. [1] Этот термин часто используется для обозначения более конкретного понятия стратегии передачи параметров [2] , которая определяет тип значения, которое передается в функцию для каждого параметра ( стратегия привязки ) [3] и следует ли оценить параметры вызова функции, и если да, то в каком порядке ( порядок оценки ). [4] Понятие стратегии сокращения отличается, [5] хотя некоторые авторы объединяют эти два термина, и определение каждого термина не получило широкого согласия. [6]

Например, при выполнении вызова функции f(a,b)сначала можно оценить аргументы aи b, сохранить результаты в ссылках или ячейках памяти ref_aи ref_b, а затем оценить тело функции с переданными ссылками. Это дает функции возможность искать значения аргументов, изменять их. их посредством присваивания , как если бы они были локальными переменными, и возвращать значения через ссылки. Это стратегия оценки по ссылке. [7]

Стратегия оценки является частью семантики определения языка программирования. Некоторые языки, такие как PureScript , имеют варианты с разными стратегиями оценки. Некоторые декларативные языки , такие как Datalog , поддерживают несколько стратегий оценки. Некоторые языки определяют соглашение о вызовах . [ нужны разъяснения ]

Стол

Это таблица стратегий оценки и репрезентативных языков по годам введения. Репрезентативные языки перечислены в хронологическом порядке, начиная с языка(ов), на которых была представлена ​​стратегия, и заканчивая известными языками, использующими эту стратегию. [8] : 434 

Заказы на оценку

Хотя порядок операций определяет абстрактное синтаксическое дерево выражения, порядок вычисления определяет порядок, в котором вычисляются выражения. Например, программа Python

def  f ( x ):  print ( x ,  end = '' )  return  xраспечатать ( ж ( 1 )  +  ж ( 2 ), конец = '' )

выходные данные 123из-за порядка вычислений Python слева направо, но аналогичная программа в OCaml :

пусть  f  x  =  print_int  x ;  Икс  ;; print_int  ( ж  1  +  ж  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]

программа Главная ; использует ЭЛТ ;  процедура PrintArray ( a : Массив целых чисел ) ; вар я : целое число ; start for i := Low ( a ) to High ( a ) do Write ( a [ i ]) ; НаписатьLn () ; конец ;               Процедура Modify ( строка : массив целых чисел ) ; начать PrintArray ( строка ) ; // 123 строка [ 1 ] := 4 ; PrintArray ( строка ) ; // 143 конец ;              Var A : Массив целых чисел ; начало A := [ 1 , 2 , 3 ] ; ПечатьАррай ( А ) ; // 123 Изменить ( А ) ; ПечатьАррай ( А ) ; // 123 конец .              

Семантический дрейф

Строго говоря, при вызове по значению никакие операции, выполняемые вызываемой подпрограммой, не могут быть видны вызывающей стороне, кроме как как часть возвращаемого значения. [16] Это подразумевает форму чисто функционального программирования в семантике реализации. Однако оборот «вызов по значению, где значение является ссылкой» стал обычным явлением, например, в сообществе Java. [36] По сравнению с традиционной передачей по значению, передаваемое значение — это не значение в его обычном значении, например целое число, которое можно записать как литерал, а внутренний дескриптор ссылки реализации . Изменения этого дескриптора ссылки видны в вызывающем объекте. Из-за видимой мутации эту форму «вызова по значению» правильнее называть вызовом путем совместного использования. [16]

В чисто функциональных языках значения и структуры данных неизменяемы, поэтому у функции нет возможности изменить какой-либо из своих аргументов. Таким образом, обычно нет семантической разницы между передачей по значению и передачей по ссылке или указателю на структуру данных, и реализации часто используют внутренний вызов по ссылке для повышения эффективности. Тем не менее, эти языки обычно описываются как языки вызова по значению.

Звонок по ссылке

Вызов по ссылке (или передача по ссылке) — это стратегия оценки, при которой параметр привязывается к неявной ссылке на переменную, используемую в качестве аргумента, а не к копии ее значения. Обычно это означает, что функция может изменять (т. е. присваивать ) переменную, используемую в качестве аргумента, — то, что будет видно вызывающей стороне. Таким образом, вызов по ссылке может использоваться для предоставления дополнительного канала связи между вызываемой функцией и вызывающей функцией. Передача по ссылке может значительно повысить производительность: вызов функции с многомегабайтной структурой в качестве аргумента не требует копирования большой структуры, а только ссылки на структуру (которая обычно представляет собой машинное слово и занимает всего несколько байт). Однако язык вызова по ссылке затрудняет программисту отслеживание последствий вызова функции и может привести к появлению мелких ошибок.

Из-за различий в синтаксисе разница между вызовом по ссылке (где ссылочный тип является неявным) и вызовом путем совместного использования (где ссылочный тип является явным) на первый взгляд часто неясна. Простой лакмусовой бумажкой является возможность написать swap(a, b)на этом языке традиционную функцию. [36] Например, на Фортране:

программа Основная неявная none целое :: a = 1 целое :: b = 2 вызов Swap ( a , b ) print * , a , b ! 2 1 содержит  подпрограмму Swap ( a , b ) целое число , намерение ( inout ) :: a , b целое число :: temp temp = a a = b b = temp end подпрограмма Swap end program Main                                     

Таким образом, намерение Фортрана inoutреализует вызов по ссылке; любая переменная может быть неявно преобразована в ссылочный дескриптор. Напротив, самое близкое, что можно получить в Java:

класс  Main { статический класс Box { int value ; public Box ( int value ) { this . значение = значение ; } } static void swap ( Box a , Box b ) { int temp = a . ценить ; а . значение = б . ценить ; б . значение = температура ; } Public static void main ( String [] args ) { Box a = new Box ( 1 ); Коробка b = новая коробка ( 2 ); поменять местами ( а , б ); Система . вне . println ( String.format ( " %d % d " , a.value , b.value ) ) ; } } // вывод: 2 1                                                        

Boxгде для введения дескриптора необходимо использовать явный тип. Java использует вызов путем совместного использования, но не вызов по ссылке. [36]

Звонок путем копирования-восстановления

Вызов путем копирования-восстановления, также известный как «копирование-вход-выход», «вызов по результату значения», «вызов по возврату значения» (как это называется в сообществе Fortran ) — это вариант вызова по ссылке. При вызове методом копирования-восстановления содержимое аргумента копируется в новую переменную, локальную для вызова вызова. Затем функция может изменить эту переменную, аналогично вызову по ссылке, но поскольку переменная является локальной, изменения не видны за пределами вызова во время вызова. Когда вызов функции возвращает значение, обновленное содержимое этой переменной копируется обратно, чтобы перезаписать исходный аргумент («восстановлено»). [37]

Семантика вызова путем копирования-восстановления во многих случаях аналогична вызову по ссылке, но отличается, когда два или более аргумента функции псевдонимируют друг друга (т. е. указывают на одну и ту же переменную в среде вызывающего объекта). При вызове по ссылке запись в один аргумент повлияет на другой во время выполнения функции. При вызове путем копирования-восстановления запись в один аргумент не повлияет на другой во время выполнения функции, но в конце вызова значения двух аргументов могут отличаться, и неясно, какой аргумент копируется первым и, следовательно, какое значение получает переменная вызывающего объекта. [38] Например, Ада указывает, что назначение копирования для каждого параметра in outили outпроисходит в произвольном порядке. [39] Из следующей программы (недопустимой в Ada 2012) [40] видно, что поведение GNAT заключается в копировании в порядке слева направо:

с  Ada.Text_IO ;  используйте  Ada.Text_IO ;процедура  Test_Copy_Restore  — это  процедура  Modify  ( A ,  B  : in  out  Integer )   начало  A  :=  A  +  1 ;  Б  :=  Б  +  2 ;  конец  изменения ;  X  :  Целое число  :=  0 ; начать  изменение ( X ,  X );  Put_Line ( "X ="  &  Integer ' Image ( X )); конец  Test_Copy_Restore ; -- $ gnatmake -gnatd.E test_copy_restore.adb; ./test_copy_restore -- test_copy_restore.adb:12:10: предупреждение: фактическое значение, доступное для записи для "A", совпадает с фактическим значением для "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 списки изменяемы и передаются при вызове путем совместного использования, поэтому:

защита  f ( a_list ):  a_list . добавить ( 1 )м  =  [] ж ( м ) печать ( м )

выводит [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 ; * а = * б ; * б = температура ; }               int main () { int a = 1 ; интервал б = 2 ; поменять местами ( &a , & б ); printf ( "%d %d" , a , b ); // 2 1 возвращаем 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 ; назначить ( temp , прочитать ( a )); назначить ( a , прочитать ( b )); назначить ( b , прочитать ( temp )); }                 int main () { int a_storage ; int * a = & a_storage ; int b_storage ; int * b = & b_storage ; назначить ( а , 1 ); назначить ( б , 2 ); поменять местами ( а , б ); printf ( "%d %d" , read ( a ), read ( b )); // 2 1 возвращаем 0 ; }                        

Поскольку в этой программе swapоперируют указателями и не могут изменять сами указатели, а только значения, на которые указывают указатели, эта точка зрения предполагает, что основная стратегия оценки C больше похожа на вызов путем совместного использования.

C++ еще больше запутывает проблему, позволяя swapобъявлять и использовать очень легкий «эталонный» синтаксис: [50]

void swap ( int & a , int & b ) { int temp = a ; а = б ; б = температура ; }               int main () { int a = 1 ; интервал б = 2 ; поменять местами ( а , б ); std :: cout << a << b << std :: endl ; // 2 1 возвращаем 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 , создание будущего вызывает сопрограмму (асинхронную функцию), которая может передаваться вызывающей стороне и, в свою очередь, возвращаться обратно при использовании значения, обеспечивая совместную многозадачность.

Стратегия является недетерминированной, поскольку оценка может происходить в любой момент между созданием будущего (т. е. когда задано выражение) и использованием значения будущего. Стратегия не является строгой, поскольку тело функции может возвращать значение до того, как будут вычислены аргументы. Однако в большинстве реализаций выполнение все равно может зависнуть при оценке ненужного аргумента. Например, программа

ж x = 1 / x g y = 1 main = печать ( g ( f 0 ))           

может либо иметь gфиниш до fи выход 1, либо может привести к ошибке из-за вычисления 1/0. [28]

Вызов по будущему аналогичен вызову по необходимости в том, что значения вычисляются только один раз. При тщательной обработке ошибок и незавершений, в частности, при прекращении фьючерсов на полпути, если определено, что они не понадобятся, вызов по будущему также имеет те же свойства завершения, что и оценка вызова по необходимости. [52] Однако вызов по будущему может выполнять ненужную спекулятивную работу по сравнению с вызовом по необходимости, например, глубокую оценку ленивой структуры данных. [28] Этого можно избежать, используя ленивые фьючерсы, которые не начинают вычисления до тех пор, пока не будет уверенности, что значение необходимо.

Оптимистическая оценка

Оптимистическая оценка — это вариант вызова по необходимости, при котором аргумент функции частично оценивается в стиле вызова по значению в течение некоторого времени (которое может быть скорректировано во время выполнения ). По истечении этого времени вычисление прерывается и функция применяется с использованием вызова по необходимости. [53] Этот подход позволяет избежать некоторых затрат времени выполнения вызова по необходимости, сохраняя при этом желаемые характеристики завершения.

Смотрите также

Рекомендации

  1. ^ Араки, Шота; Нисидзаки, Син-я (ноябрь 2014 г.). «Оценка исчислений RPC и RMI по имени». Теория и практика вычислений. п. 1. дои : 10.1142/9789814612883_0001. ISBN 978-981-4612-87-6. Проверено 21 августа 2021 г.
  2. ^ Турбак, Франклин; Гиффорд, Дэвид (18 июля 2008 г.). Концепции проектирования в языках программирования. МТИ Пресс. п. 309. ИСБН 978-0-262-30315-6.
  3. ^ Кранк, Эрик; Феллейзен, Матиас (1991). «Передача параметров и лямбда-исчисление». Материалы 18-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования — POPL '91 . п. 2. CiteSeerX 10.1.1.23.4385 . дои : 10.1145/99583.99616. ISBN  0897914198. S2CID  5782416.
  4. ^ abc Вильгельм, Рейнхард; Зайдль, Гельмут (10 ноября 2010 г.). Проектирование компилятора: виртуальные машины. Springer Science & Business Media. п. 61. ИСБН 978-3-642-14909-2.
  5. ^ Нита, Стефания Лоредана; Михайлеску, Мариус (2017). "Введение". Практический параллельный Haskell . п. 3. дои : 10.1007/978-1-4842-2781-7_1. ISBN 978-1-4842-2780-0.
  6. ^ Пирс, Бенджамин К. (2002). Типы и языки программирования. МТИ Пресс . п. 56. ИСБН 0-262-16209-1.
  7. ^ Дэниел П. Фридман; Митчелл Ванд (2008). Основы языков программирования (третье изд.). Кембридж, Массачусетс: MIT Press . ISBN 978-0262062794.
  8. ^ Аб Скотт, Майкл Ли (2016). Прагматика языка программирования (Четвертое изд.). Уолтем, Массачусетс: Эльзевир. ISBN 9780124104778.
  9. ^ «Избегайте ненужных копий данных — MATLAB и Simulink». www.mathworks.com . Проверено 28 января 2023 г.
  10. ^ Хасти, Ребекка. «Передача параметров». CS 536: Введение в языки программирования и компиляторы . Университет Висконсина . Проверено 22 августа 2021 г.
  11. ^ Дж. А. Робинсон (январь 1965 г.). «Машинно-ориентированная логика, основанная на принципе разрешения». Журнал АКМ . 12 (1): 23–41. дои : 10.1145/321250.321253 . S2CID  14389185.; Здесь: разд.5.8, стр.32
  12. ^ Дж. А. Робинсон (1971). «Вычислительная логика: унификация вычислений». Машинный интеллект . 6 : 63–72.
  13. ^ Банди, Алан; Валлен, Линкольн (1984). «САСЛ». Каталог инструментов искусственного интеллекта . п. 117. дои : 10.1007/978-3-642-96868-6_222. ISBN 978-3-540-13938-6. Вероятно, это был первый язык, который систематически использовал возможности ленивых вычислений.
  14. Фэй, Колин (30 июля 2018 г.). «О ленивой оценке». R-блогеры . Проверено 21 августа 2021 г.
  15. ^ Уодсворт, Кристофер П. (1971). Семантика и прагматика лямбда-исчисления (доктор философии). Оксфордский университет.
  16. ^ abcde Лисков, Барбара; Аткинсон, Расс; Блум, Тоби; Мосс, Элиот; Шафферт, Крейг; Шайфлер, Крейг; Снайдер, Алан (октябрь 1979 г.). «Справочное руководство CLU» (PDF) . Лаборатория компьютерных наук . Массачусетский Институт Технологий. стр. 14–15. Архивировано (PDF) из оригинала 22 сентября 2006 г. Проверено 19 мая 2011 г.
  17. ^ «PHP: Передача по ссылке — Руководство» . www.php.net . Проверено 4 июля 2021 г.
  18. Вагнер, Билл (12 апреля 2023 г.). «Передача параметров. Руководство по программированию на C#». Документы Майкрософт . Проверено 10 сентября 2023 г.
  19. ^ Доллард, Кэтлин (15 сентября 2021 г.). «Передача аргументов по значению и по ссылке — Visual Basic». Документы Майкрософт . Проверено 10 сентября 2023 г.
  20. ^ ab «История C++». ru.cppreference.com . Проверено 11 июня 2022 г.
  21. Филипек, Бартломей (16 августа 2021 г.). «Строгий порядок вычисления выражений в C++17». Истории С++ . Проверено 24 августа 2021 г.
  22. ^ Аб Абельсон, Гарольд ; Сассман, Джеральд Джей (1996). «Нормальный порядок и аппликативный порядок». Структура и интерпретация компьютерных программ (2-е изд.). Кембридж, Массачусетс: MIT Press . ISBN 0-262-01153-0.См. также сноску Temp 576.
  23. Риз, Ричард М. (14 октября 2015 г.). Изучение функционального программирования на Java. Packt Publishing Ltd. с. 106. ИСБН 978-1-78528-935-4.
  24. ^ Антани, Вед; Тиммс, Саймон; Мантила, Дэн (31 августа 2016 г.). JavaScript: функциональное программирование для разработчиков JavaScript. Packt Publishing Ltd. с. 614. ИСБН 978-1-78712-557-5.
  25. ^ Сикорд, Роберт К. «EXP30-C. Не зависит от порядка оценки побочных эффектов». SEI CERT Стандарт кодирования C. Университет Карнеги Меллон . Проверено 23 августа 2021 г.
  26. ^ Англаде, С.; Лакрамп, Джей Джей; Кейннек, К. (октябрь 1994 г.). «Семантика сочетаний в схеме» (PDF) . Указатели Lisp ACM SIGPLAN . VII (4): 15–20. дои : 10.1145/382109.382669. S2CID  2987427.
  27. ^ «Почему аргументы функции OCaml оцениваются справа налево?» ОКамл . 30 ноября 2017 г.
  28. ^ abcde Tremblay, G. (апрель 2000 г.). «Снисходительная оценка не является ни строгой, ни ленивой». Компьютерные языки . 26 (1): 43–66. CiteSeerX 10.1.1.137.9885 . дои : 10.1016/S0096-0551(01)00006-6. 
  29. ^ Джордж, Лай (март 1987 г.). Эффективная оценка нормального порядка посредством информации о строгости (MSc). Университет Юты. п. 10.
  30. ^ Борнинг, Алан (осень 1999 г.). «Аппликативное и нормальное вычисление порядка в функциональных языках» (PDF) . CSE 505: Концепции языков программирования . Университет Вашингтона . Проверено 23 августа 2021 г.
  31. ^ Маццола, Гуэрино; Мильмейстер, Жерар; Вайсманн, Джоди (21 октября 2004 г.). Комплексная математика для ученых-компьютерщиков 2. Springer Science & Business Media. п. 323. ИСБН 978-3-540-20861-7.
  32. ^ Аб Штурм, Оливер (11 апреля 2011 г.). Функциональное программирование на C#: классические методы программирования для современных проектов. Джон Уайли и сыновья. п. 91. ИСБН 978-0-470-74458-1.
  33. ^ Марлоу, Саймон. «Почему я не могу получить трассировку стека?». Семинар разработчиков Haskell 2012 . Проверено 25 августа 2021 г.
  34. ^ Нильссон, Хенрик (1999). «Трассировка по частям: доступная отладка для ленивых функциональных языков». Материалы четвертой международной конференции ACM SIGPLAN по функциональному программированию . стр. 36–47. CiteSeerX 10.1.1.451.6513 . дои : 10.1145/317636.317782. ISBN  1581131119. S2CID  13954359.
  35. ^ «Параметры открытого массива». www.freepascal.org . Проверено 20 января 2024 г.
  36. ^ abcd «Java — это передача по значению, черт возьми!». 16 мая 2001 года . Проверено 24 декабря 2016 г.
  37. ^ Коэнен, Франс. «ПЕРЕДАЧА ПАРАМЕТРОВ». cgi.csc.liv.ac.uk. _ Проверено 22 января 2024 г.
  38. ^ «Вызов по ссылке, проблемы с псевдонимами» (PDF) . Курс MPRI 2-36-1: Проверка программы (конспекты лекций) . п. 53.
  39. ^ Справочное руководство по языку Ada 2022 (PDF) , 13 октября 2023 г., стр. 215
  40. ^ Барнс, Джон (2013). Обоснование Ada 2012: язык, стандартные библиотеки (PDF) . Гейдельберг: Спрингер. п. 15-16,87-88. ISBN 978-3-642-45210-9.
  41. ^ Терлоу, Роберт (май 2009 г.). «RPC: Спецификация протокола удаленного вызова процедур, версия 2». www.tools.ietf.org . IETF . Проверено 7 апреля 2018 г.
  42. ^ Лунд, Фредрик. «Вызов по объекту». Effbot.org . Архивировано из оригинала 19 мая 2011 г. Проверено 19 мая 2011 г.
  43. ^ Джонс, Рис Прайс (2010). «Вызов схемы по значению?». CS 145 Языки программирования. Лабораторная работа 9: Передача параметров . Университет Джорджа Вашингтона. Архивировано из оригинала 16 октября 2014 года . Проверено 20 января 2024 г.
  44. ^ «Процедуры библиотеки Tcl — страница руководства Tcl_Obj» . www.tcl.tk. _
  45. ^ «CA1021: Избегайте выходных параметров» . Майкрософт. 15 ноября 2016 г.
  46. ^ Лео, Рэй (ноябрь 1996 г.). Маленький C++ (сделано просто). LeoSudo Inc., стр. 79–80. ISBN 978-0-9654634-1-6.
  47. Дандамуди, Шиварама П. (15 июля 2005 г.). Руководство по программированию на языке ассемблера в Linux. Springer Science & Business Media. п. 232. ИСБН 978-0-387-25897-3.
  48. ^ Шривастава, СК; Шривастава, Дипали (6 июня 2018 г.). C в глубине. Публикации БПБ. п. 206. ИСБН 978-93-87284-94-4.
  49. ^ «Изменяемые переменные и ссылочные типы». okmij.org . Проверено 20 января 2024 г.
  50. Вермейр, Дирк (28 июня 2011 г.). Мультипарадигмальное программирование с использованием C++. Springer Science & Business Media. стр. 10–11. ISBN 978-1-4471-0311-0.
  51. ^ МакКоллин, Томас Гвинфрин; Морелл, Тобиас. «Игра парадигм: исследование удобства использования функциональных идиом в программировании игрового процесса» (PDF) . Ольборгский университет. п. 6 . Проверено 11 января 2022 г.
  52. ^ аб Шаузер, Клаус Э.; Гольдштейн, Сет К. (1995). «Какой степени нестрогости требуют мягкие программы?» (PDF) . Материалы седьмой международной конференции «Функциональные языки программирования и компьютерная архитектура — FPCA '95» . стр. 216–225. дои : 10.1145/224164.224208. ISBN 0897917197. S2CID  2045943 . Проверено 7 января 2022 г.
  53. ^ Энналс, Роберт; Джонс, Саймон Пейтон (август 2003 г.). «Оптимистическая оценка: стратегия быстрой оценки для нестрогих программ».

дальнейшее чтение

Внешние ссылки