Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Предикаты (функции) сравнения
(eq e1 e2) Функция сравнивает значения своих аргументов, которые должны быть атомами-идентификаторами. В случае их совпадения (идентичности) значение функции равно T, иначе – (). (eql e1 e2) В отличие от предыдущей функции eql сравнивает значения своих аргументов, которыми могут быть не только атомы-идентификаторы, но и атомы-числа. Если они равны, то значение функции равно T, иначе - (). (equal e1 e2) Функция производит сравнение двух произвольных S-выражений - значений своих аргументов. Если они равны (имеют одинаковую структуру и состоят из одинаковых атомов), то значение функции равно T, иначе - (). (neq e1 e2) Аналог, но значения аргументов сравниваются на "не равно". (member a l) Функция производит поиск атома, являющегося значением первого ее аргумента, в списке (на верхнем его уровне), являющемся вторым аргументом. В случае успеха поиска значение функции равно T, иначе - (). (gt n1 n2) или (> n1 n2) Значениями аргументов этой функции должны быть числа. Если первое из них больше второго, то значение функции равно T, иначе – (). (lt n1 n2) или (< n1 n2) Аналог, но числа сравниваются на "меньше". Логические функции Так называются три функции, реализующие основные логические операции. (not e) Эта функция, реализующая "отрицание", является дубликатом функции null: если значение аргумента равно () ("ложь"), то функция выдает результат T ("истина"), а при любом другом значении аргумента выдает результат (). (and e1 e2 ... ek) (k ≥ 1) Это "конъюнкция". Функция по очереди вычисляет свои аргументы. Если значение очередного из них равно () ("ложь"), то функция, не вычисляя оставшиеся аргументы, заканчивает свою работу со значением (), а иначе переходит к вычислению следующего аргумента. Если функция дошла до вычисления последнего аргумента, то с его значением она и заканчивает свою работу. (or e1 e2 ... ek) (k ≥ 1) Это "дизъюнкция". Функция по очереди вычисляет свои аргументы. Если значение очередного из них не равно () ("ложь"), то функция, не вычисляя оставшиеся аргументы, заканчивает свою работу со значением этого аргумента, в противном случае она переходит к вычислению следующего аргумента. Если функция дошла до вычисления последнего аргумента, то с его значением она и заканчивает свою работу. К числу логических функций можно отнести и лисповское условное выражение: [cond (p1 e1,1 e1,2 ... e1,k1) ... (pn en,1 en,2 ... en,kn)] где (n≥1, ki≥1) Функция cond последовательно вычисляет первые элементы своих аргументов – обращения к предикатам pi. Если все они имеют значение () ("ложь"), тогда функция заканчивает свою работу с этим же значением. Но если был обнаружен предикат pi, значение которого отлично от (), т.е. он имеет значение "истина", тогда функция cond уже не будет рассматривать остальные предикаты, а последовательно вычислит формы ei,j из этого i-го аргумента и со значением последнего из них закончит свою работу. Заметим, что поскольку значения предыдущих форм из этого аргумента нигде не запоминаются, то в качестве этих форм имеет смысл использовать только такие, которые имеют побочный эффект, например, обращение к функции присвоения значения.
2.9. Определения функций. Формализм их задания Механизм объявления функций заимствован из лямбда-исчисления Черча, то есть основан на методе представления «безымянных функций» с помощью вычислимых выражений. «Безымянная» функция (или лямбда-выражение) представляет собой совокупность набора формальных переменных и действия с ними. Пример лямбда-выражения: (lambda (х у) (+ х у)) Само по себе лямбда-выражение не воспринимается интерпретатором, а вот лямбда-выражение, примененное к фактическим аргументам, уже вычислимо: ((lambda (х у) (+ х у)) 1 2) => 3 При вызове лямбда-выражения фактические параметры по определенным правилам связываются с формальными и над ними выполняется заданное действие. Таким образом, каждый раз, когда нам нужна функция, мы можем записать необходимое лямбда-выражение, примененное к фактическим параметрам. Ясно, что это весьма неудобно (хотя и правильно с «идейной» точки зрения), поэтому Lisp предоставляет возможность именования конкретных лямбда-выражений для их последующего повторного использования. Для этого служит встроенная функция defun, к которой возможны следующие (равноценные) обращения: (defun f (lambda (v1 v2 ... vn) e)) или (defun f (v1 v2 ... vn) e). Вычисление функции defun в качестве побочного эффекта приводит к появлению в программе новой функции с именем f ; vi – формальные параметры новой функции (n≥0), а e - форма, зависящая от vi. Заметим, что таким образом определяется обычная лисп-функция, т.е. функция с фиксированным количеством аргументов, которые всегда вычисляются при обращении к ней. При последующем обращении к этой уже определенной функции (f a1 a2 ... an) сначала вычисляются аргументы (фактические параметры) ai, затем вводятся локальные переменные vi, которым присваиваются значения соответствующих аргументов ai, и далее вычисляется форма e при этих значениях переменных vi, после чего эти переменные уничтожаются. Значением данной формы становится значение функции f при аргументах ai. Лексические переменные (формальные параметры функций) связаны лишь в пределах той формы, в которой они определены, то есть изменение их значений не влияет на значения одноименных внешних переменных. В силу рекурсивной природы списков как таковых для определения функций можно использовать рекурсию, хотя возможности Лиспа не исключают и обычные, императивные определения. В качестве примера можно привести следующее рекурсивное определение функции вычисления факториала: (defun myfactor (х) (cond((equal х 1) 1) (t (* x (myfactor (- x 1)))))) Фундаментальное значение рекурсии состоит в ее применении всюду, где требуются циклические вычисления, поскольку «чистая» функциональная программа не содержит операторов цикла.
Функционалы Кроме обычных функций в Lisp существует также возможность объявления функций более высокого порядка, или функционалов. Функционал – это функция, одним из аргументов которой, в свою очередь, является функция. В различных случаях функциональный аргумент может использоваться и как данные (в том случае, если он не влияет на вычисления), и как обычная функция (в том случае, если он используется как средство, определяющее вычисления): (car ’(lambda (x) (list x))) => lambda ;; CAR - функция, ;; лямбда-выражение - данные; ((lambda (x) (list x)) ’car) => (car) ;; CAR - данные, ;; лямбда-выражение – функция Функционал – это функция, в которой функциональный аргумент используется в позиции и в роли функции. Пример пояснит ситуацию. Часто используются так называемые отображающие функционалы МАРx (где x—CAR или CDR), применяющие функциональные аргументы последовательно к CAR или CDR списка и составляющие список результатов: (mapcar ’(lambda (x) (print x)) ’(1 2 3)) => 1\n2\n3\n (mapcdr ’(lambda (x) (print (car x))) ’(1 2 3)) => 2\n3\n nil\n
Свойства символов В Lisp каждый символ имеет так называемые свойства. Удобно представлять символы в виде структуры из нескольких значений: непосредственно самого значения символа, а также некоторых присвоенных ему именованных значений, называемых свойствами. На самом деле свойства представляются списком, хранящимся вместе с символом (список свойств, property list, proplist), следующего вида: (имя1 значение1 имя2 значение2. . . ), например, у символа «кошка» может быть такой список свойств: (шерсть густая цвет-шерсти белый цвет-глаз голубой) В Common Lisp (одна из стандартизованных реализаций языка Лисп) получение определенного свойства символа выполняется с помощью функции get: (get ’кошка ’цвет-шерсти) => белый Присваивание же выполняется с помощью объединения обобщенного присваивания setf и get. Причем подобным образом может быть и заведено новое свойство: (setf (get ’кошка ’природная-еда) ’мыши) => мыши (get ’кошка ’природная-еда) => мыши Полный список пользовательских свойств может быть получен с помощьюфункции symbolplist: (symbol-plist ’кошка) => (природная-еда мыши) Каждый символ в Lisp помимо определенных пользователем свойств содержит также список системных свойств, таких, как, например, лямбда-выражение (если с данным символом связано определение функции), тип символа и т. д. Эти свойства изменяются с помощью описанных выше функций set, defun и пр. Таким образом, является ли данный символ функцией или нет, принадлежит ли он тому или иному типу и т. п., является свойством самого символа, что позволяет легко манипулировать этими свойствами (попробуйте в С убрать у main() свойство быть функцией). Эта возможность Lisp позволяет заметно облегчить написание программ, управляемых данными, семантических сетей, а также объектно-ориентированных программ. |
Последнее изменение этой страницы: 2019-06-20; Просмотров: 180; Нарушение авторского права страницы