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

Содержимое удалено Содержимое добавлено
Нет описания правки
Нет описания правки
Строка 1:
<div style="max-width:60em;margin:1em auto 0 4%;">
Если вы уже знакомы с каким-нибудь императивнымалголоподобным языком типа [[Категория:Си|Си]] или PerlПёрла, то понятие '''функции''' в лиспеЛиспе может показаться странным, но оно значительно ближе к математическому понятиюявлению функции, чем «функции» Си, которые повернее сутибы являютсяназвать более процедурами. Функция в лиспеЛиспе есть однозначное отображение множества исходных данных на множество еееё значений. Так же, как и в математике, уУ функции может быть любоепроизвольно количествомного аргументов, их можетот ненуля бытьдо совсем<s>бесконечности</s> любого конечного числа, но обязательно должно быть хотя бы одно значение. ВОбычная лиспедля принятамногих языков префиксная запись вызова функций, но в отличие от привычного f(x,y) -> z это пишется как (f x y) -> z. Не смотря на внешнее неудобство понимание такой записи - дело привычки, и через некоторое время вы увидите его преимущества.:
<source lang=c>plus(2,2)</source>
несколько видоизменяется в силу отсутствия синтаксиса: идентификатор ("имя" функции, спецоператора или [[Лисп/Макросы|макровызова]]) становится головным элементом… да, списка:
<source lang=lisp>(plus 2 2)</source>
 
В чистом функциональном лиспе<ref>Являющемся (pureстрогим lisp)подмножеством любого из диалектов</ref> функции не должны обладать [[w:Побочный_эффект_(программирование)|побочным эффектом]], то есть изменять значения глобальных переменных с нелокальным состоянием. В противном случае, при нескольких вызовах одной функции могут быть получены разные значения, что противоречитзапутывает концепциилюбую [[w:Функциональное_программирование|функционального программирования]]. В современных диалектах лиспа есть функции с побочными эффектами - так называемые псевдофункции. Поройсложную онипрограммную необходимысистему, нои ихчего использованиестремится должноизбежать быть предельно ограничено[[w:функциональное_программирование|функциональное_программирование]].
 
Определение функции основано на [[w:Лямбда_исчисление|лямда-исчислении]]. Исходный вариант записи лямда-выражения, предложенный его автором Черчем[[w:Алонзо Чёрч|Чёрчем]], выглядит как
<math>\lambda(x1x_1,x2x_2...)fn</math>. Лисп-запись выглядит так: <code>(lambda (x1 x2 ...) fn)</code>. x1, x2 ... - формальныесвободные параметры, тои, есть онитак, могут быть безболезненно заменены на другие без изменении значения лямбда-выражения. Благодаря этому лямбда-выражения способны обеспечить больший уровень абстракции, чем обычные функции.
 
Например, сумму квадратов на языке лямбда-выражений можно определить как <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). Это возможно, если вы предварительно определите функцию сумма-квадратов.
<source lang="lisp">
>> (defun сумма-квадратов (x y)
((lambda (a b) (+ (* a a) (* b b)))
x y))
</source>
Для…но не пугайтесь: для удбства эта запись может быть сокрвщенасокращена до
<source lang="lisp">
>> (defun сумма-квадратов (x y)
(+ (* x x) (* y y)))
</source>
Одно из преимуществ столь непривычных особенностей языка лиспЛисп в том, что вы можете написать нечто типа
<source lang="lisp">
>> ((lambda (x)
((lambda (y)
(list x y))
'second))
'first)
<< (first second)
</source>
Здесь лямбдалямда-выражение является '''телом''' другого лямда-выражения. Оно так же может быть одним из его аргументов.
 
Посмотреть ранее заданное определение функции fn, которая уже была определена, можно с помощью функции <code>symbol-function</code>:
<source lang="lisp">
>> (symbol-function 'сумма-квадратов)
Строка 35 ⟶ 37 :
(block сумма-квадратов (+ (* x x) (* y y)))>
</source>
Штрих перед названием функции поставлен неслучайно. В лиспеЛиспе любое имя соответствует некоторому символу. Имя функции - не исключение, то есть значение символа "«<code>сумма-квадратов"</code>» - не определение функции; оно неопределено, пока не будет присвоено вручную (например, через <code>setq или еще что-то</code>.) Штрих - это сокращенная запись функцииспецоператора <code>quote</code>, она сообщаетсообщающая интерпретатору, что не нужно вычислятьвывести значениеимя данного символа, абез вместо этого нужно вывестивычисления его имязначения.
<source lang="lisp">
>> (symbol-function сумма-квадратов) ; это выдаст ошибку: переменной сумма-квадратов не присвоено значение
Строка 41 ⟶ 43 :
>> (symbol-function 'сумма-квадратов) ; так лучше всего
</source>
Если все аргументы лямбда-выражения не должны вычисляться, то удобно использовать <code>nlambda</code> вместо <code>lambda</code>.
 
Функции <code>quote</code>’е противопоставлена функцияпротивопоставлен <code>eval</code>, которая принудительно вычисляетвычисляющий значение выражения.
<source lang="lisp">
>> (quote сумма-квадратов) => сумма-квадратов
Строка 49 ⟶ 51 :
>> (quote (eval (quote сумма-квадратов))) => (eval 'sum)
</source>
В последнем случае квотируется не только "<code>сумма-квадратов"</code>, но и сам eval!
[[Категория:Функциональное программирование]]