Лисп/Функции: различия между версиями

Содержимое удалено Содержимое добавлено
викификация, орфография
м <source> -> <syntaxhighlight> (phab:T237267)
 
Строка 1:
<div style="max-width:60em;margin:1em auto 0 4%;">
Если вы уже знакомы с каким-нибудь алголоподобным языком типа [[Язык Си в примерах|Си]] или Пёрла, то понятие '''функции''' в Лиспе может показаться странным, но оно значительно ближе к математическому явлению функции, чем «функции» Си, которые вернее бы назвать более процедурами. Функция в Лиспе есть однозначное отображение множества исходных данных на множество её значений. У функции может быть произвольно много аргументов, — от нуля до любого конечного числа, — но обязательно должно быть хотя бы одно значение. Обычная для многих языков префиксная запись вызова функций:
<sourcesyntaxhighlight lang=c>plus(2,2)</sourcesyntaxhighlight>
несколько видоизменяется в силу отсутствия синтаксиса: идентификатор («имя» функции, спецоператора или [[Лисп/Макросы|макровызова]]) становится головным элементом… да, списка:
<sourcesyntaxhighlight lang=lisp>(plus 2 2)</sourcesyntaxhighlight>
 
В чистом функциональном лиспе (являющемся строгим подмножеством любого из диалектов) функции не должны обладать [[w:Побочный эффект (программирование)|побочным эффектом]], то есть изменять значения переменных с нелокальным состоянием. В противном случае, при нескольких вызовах одной функции могут быть получены разные значения, что запутывает любую сложную программную систему, и чего стремится избежать [[w:функциональное программирование|функциональное программирование]].
Строка 11:
 
Например, сумму квадратов на языке лямбда-выражений можно определить как <code>(lambda (x y) (+ (* x x) (* y y)))</code>. Вызов лямбда-функции с конкретными значениями <code>((lambda (x y) (+ (* x x) (* y y))) 2 3) => (+ (* 2 2) (* 3 3)) => 13</code> может быть сделан единожды, при желании вызвать такую функцию еще раз необходимо повторить запись еще раз. Это неудобно. Было бы удобнее написать нечто типа (сумма-квадратов 2 3). Это возможно, если вы предварительно определите функцию сумма-квадратов.
<sourcesyntaxhighlight lang="lisp">
(defun сумма-квадратов (x y)
((lambda (a b) (+ (* a a) (* b b)))
x y))
</syntaxhighlight>
</source>
…но не пугайтесь: для удобства эта запись может быть сокращена до
<sourcesyntaxhighlight lang="lisp">
(defun сумма-квадратов (x y)
(+ (* x x) (* y y)))
</syntaxhighlight>
</source>
Одно из преимуществ столь непривычных особенностей языка Лисп в том, что вы можете написать нечто типа
<sourcesyntaxhighlight lang="lisp">
((lambda (x)
((lambda (y)
Строка 28:
'second))
'first)
</syntaxhighlight>
</source>
Здесь лямбда-выражение является '''телом''' другого лямбда-выражения. Оно так же может быть одним из его аргументов.
 
Посмотреть ранее заданное определение функции можно с помощью функции <code>symbol-function</code>:
<sourcesyntaxhighlight lang="lisp">
>> (symbol-function 'сумма-квадратов)
<< #<function сумма-квадратов (x y) (declare (system::in-defun сумма-квадратов))
(block сумма-квадратов (+ (* x x) (* y y)))>
</syntaxhighlight>
</source>
Штрих перед названием функции поставлен неслучайно. В Лиспе любое имя соответствует некоторому символу. Имя функции — не исключение, то есть значение символа «<code>сумма-квадратов</code>» — не определение функции; оно неопределено, пока не будет присвоено вручную (например, через <code>setq</code>.) Штрих — это сокращенная запись спецоператора <code>quote</code>, сообщающая интерпретатору, что нужно вывести имя данного символа без вычисления его значения.
<sourcesyntaxhighlight lang="lisp">
>> (symbol-function сумма-квадратов) ; это выдаст ошибку: переменной сумма-квадратов не присвоено значение
>> (symbol-function (quote сумма-квадратов)) ; это правильно, но долго
>> (symbol-function 'сумма-квадратов) ; так лучше всего
</syntaxhighlight>
</source>
Если все аргументы лямбда-выражения не должны вычисляться, то удобно использовать <code>nlambda</code> вместо <code>lambda</code>.
 
<code>quote</code>’е противопоставлен <code>eval</code>, принудительно вычисляющий значение выражения.
<sourcesyntaxhighlight lang="lisp">
>> (quote сумма-квадратов) => сумма-квадратов
>> (eval (quote сумма-квадратов)) => ошибка!
>> (quote (eval (quote сумма-квадратов))) => (eval 'sum)
</syntaxhighlight>
</source>
В последнем случае квотируется не только <code>сумма-квадратов</code>, но и сам eval!