Приведенные ранее описания и правила записи функций и выражений в этой лекции получат более
строгое определение. Начнем с синтаксического
Синтаксис данных в
атом ::= БУКВА конец_атома
Это правило констатирует, что атомы начинаются с буквы.
конец_атома ::= пусто
| БУКВА конец_атома
| цифра конец_атома
Это правило констатирует, что после первой литеры в изображении атома могут быть как буквы, так и цифры.
В
S-выражение ::= атом
| (S-выражение . S-выражение)
| (S-выражение ... )
Данное правило констатирует, что S-выражения — это или атомы, или узлы из пары S-выражений, или списки из S-выражений. (Три точки означают, что допустимо любое число вхождений предшествующего вида объектов, включая ни одного.)
Согласно такому правилу "()" есть допустимое S-выражение. Оно в языке .
Базовая система представления данных — точечная нотация, хотя на практике запись в виде списков удобнее.
Любой список можно представить
() = NIL (a . NIL) = (a) - - - (a1 . ( ... (aK . NIL) ... )) = (a1 ... aK)
Такая единая структура данных оказалась вполне достаточной для представления сколь угодно
сложных программ. Дальнейшее определение языка
Другие правила представления данных нужны лишь при расширении и специализации лексики языка (числа, строки, имена особого вида и т.п.). Они не влияют ни на общий синтаксис языка, ни на строй его понятий, а лишь характеризуют разнообразие сферы его конкретных приложений.
Синтаксис программ является конкретизацией синтаксиса данных, а именно — выделением из класса
S-выражений подкласса вычислимых выражений (форм), т.е. данных, имеющих смысл как выражения языка
и приспособленных к вычислению. Внешне это выглядит как объявление объектов, заранее известных в языке, и
представление разных форм,
Выполнение программы устроено как интерпретация данных, представляющих выражения, имеющие значение.
Ниже приведены синтаксические правила для обычных конструкций, к которым относятся
идентификатор ::= атом
Идентификатор — это подкласс атомов, используемых при именовании неоднократно используемых объектов программы — функций и переменных. Предполагается, что идентифицируемые объекты размещаются в памяти так, что по идентификатору их можно найти.
Понятие "идентификатор" выделено для того, чтобы по мере развития определения атома не требовалось
на все виды атомов искусственно распространять
форма ::= константа
| переменная
| (функция аргумент ... )
| (COND (форма форма) (форма форма) ... )
константа ::= (QUOTE S-выражение)
| 'S-выражение
переменная ::= идентификатор
Переменная — это подкласс идентификаторов, которым сопоставлено многократно используемое значение, ранее вычисленное в подходящем контексте. Подразумевается, что одна и та же переменная в разных контекстах может иметь разные значения.
Таким образом, класс форм — это объединение класса переменных и подкласса списков,
начинающихся с QUOTE, или с представления некоторой функции.
аргумент ::= форма
Форма — это выражение, которое может быть QUOTE, блокирующей вычисление. Представление
констант с помощью QUOTE устанавливает границу, далее которой вычисление не идет.
Использование апострофа "'" — просто сокращенное обозначение для удобства набора внешних форм.
Константные значения аргументов характерны при тестировании и демонстрации программ.
Если форма представляет собой переменную, то ее значением должно быть S-выражение, связанное с
этой переменной до момента
Третья ветвь определения гласит, что можно написать функцию, затем перечислить ее аргументы, и все это как общий список заключить в скобки.
Аргументы представляются формами. Это означает, что допустимы композиции функций.
Обычно аргументы вычисляются в порядке вхождения в
Последняя ветвь определяет формат условного выражения. Согласно этому формату условное выражение
строится из размещенных в двухэлементном списке синтаксически различимых позиций
для пропозициональных термов и обычных форм. Двухэлементные списки из определения
условного выражения рассматриваются как представление предиката и соответствующего ему S-выражения.
Значение условного выражения определяется перебором предикатов по порядку, пока не
найдется форма, значение которой отлично от , что означает логическое значение "истина".
Строго говоря, такая форма должна быть найдена непременно. Тогда вычисляется S-выражение, размещенное
вторым элементом этого же двухэлементного списка. Остальные предикаты и формы условного выражения не
вычисляют (логика Маккарти), их формальная корректность или определенность не влияют на
существование результата.
Разница между пропозициональными и обычными формами заключается лишь в трактовке их результатов. Любая форма может играть роль предиката.
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
Название — это подкласс идентификаторов, определение которых хранится в памяти, но оно может не подвергаться влиянию контекста вычислений.
Таким образом, класс функций — это объединение класса назва-ний и подкласса трехэлементных списков, начинающихся с LAMBDA или LABEL.
Функция может быть представлена просто именем. В таком случае ее смысл должен быть заранее известен. Функция может быть введена с помощью лямбда-выражения, устанавливающего соответствие между аргументами функции и связанными переменными, упоминаемыми в теле ее определения (в определяющей ее форме). Форма из определения функции может включать переменные, не включенные в лямбда-список, — так называемые свободные переменные. Их значения должны устанавливаться на более внешнем уровне. Если функция рекурсивна, то следует объявить ее имя с помощью специальной функции LABEL. (Используемая в примерах , по существу, совмещает эффекты LABEL и LAMBDA.)
форма ::= переменная
| (QUOTE S-выражение)
| (COND (форма форма) ... (форма форма))
| (функция аргумент ... )
аргумент ::= форма
переменная ::= идентификатор
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
идентификатор ::= атом
S-выражение ::= атом
| (S-выражение . S-выражение)
| (S-выражение ...)
атом ::= БУКВА конец_атома
конец_атома ::= пусто
| БУКВА конец_атома
| цифра конец_атома
Интерпретация или
Определим eval от аргумента expr — выражения, являющегося произвольной вычислимой формой языка
Универсальная функция должна предусматривать основные виды вычисляемых форм, задающих значения аргументов, а также представления функций, в соответствии со сводом приведенных выше правил языка. При
x, elem, смысл которых зависит от контекста, в котором они вычисляются;QUOTE, можно просто извлечь из списка ее аргументов. Например, значением константы (QUOTE T) является атом T, обычно символизирующий значение "истина";(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
)
должна обеспечивать выбор ветви в зависимости от атомарности значения аргумента. Семантика NIL . Иногда это придает условным выражениям лаконичность;(first (CAR x)) внутренняя функция CAR сначала получит в качестве своего аргумента значение переменной x, а потом свой результат передаст как аргумент более first ;CAR, CDR , CONS и т.п., и имена функций, введенных в программе, например first. Для встроенных функций (LAMBDA (x)
(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
) )
зависит от одного аргумента, значение которого должно быть связано с переменной x. В определении используется first, которая должна быть определена в более внешнем контексте;LABEL, то понадобится сохранить имя функции с соответствующим ее определением так, чтобы корректно выполнялись рекурсивные вызовы функции. Например, предыдущее LAMBDA-определение LABEL, первый аргумент которой — fisrt, (LABEL first
(LAMBDA (x)
(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
) ) )
Таким образом,
cons , car, cdr , atom , eq );lambda, label );quote, cond , eval ).В большинстве языков программирования аналоги первых двух подсистем нацелены на обработку элементарных данных и конструирование составных значений, кроме того, иначе установлены границы между подсистемами.
Прежде чем дать определение
Начнем с общих методов обработки S-выражений.
(DEFUN among (x y)
(COND
((ATOM y) (EQ x y))
((among x (CAR y)) (QUOTE T))
((QUOTE T) (among x (CDR y) ))
) )
(among 'A '(C (A B))) ; = T
(among 'A '(C D B)) ; = NIL
Символ " ; " - начало примечания (до конца строки).
EQUAL — предикат, проверяющий равенство двух S-выражений. Его значение "истина" для идентичных аргументов и "ложь" для различных. (Элементарный предикат EQ определен только для атомов.) Определение EQUAL иллюстрирует условное выражение внутри условного выражения (двухуровневое условное выражение и equalнаправленная рекурсия).
(DEFUN equal (x y)
(COND
((ATOM x) (COND
((ATOM y) (EQ x y))
((QUOTE T) (QUOTE NIL))
) )
((equal (CAR x)(CAR y))
(equal (CDR x)(CDR y)) )
((QUOTE T) (QUOTE NIL) )
) )
(equal '(A (B)) '(A (B))) ; = T
(equal '(A B) '(A . B)) ; = NIL
x, y, z, строящая результат замены S-выражением x всех вхождений y в S-выражение z.
(DEFUN subst (x y z)
(COND
((equal y z) x)
((ATOM z) z)
((QUOTE T)(CONS
(subst x y (CAR z))
(subst x y (CDR z))
)
)
) )
(subst '(x . A) 'B '((A . B) . C)) = ((A x . A) . C)
Использование equal в этом определении позволяет осуществлять
(subst 'x '(B C D) '((A B C D)(E B C D)(F B C D)))
; = ((A . x) (E . x) (F . x))
(DEFUN null (x)
(COND
((EQ x (QUOTE NIL)) (QUOTE T))
((QUOTE T) (QUOTE NIL))
) )
При необходимости можно компоненты точечной пары разместить в двухэлементном списке функцией PAIR_TO_LIST, и наоборот, из первых двух элементов списка построить точечную
(DEFUN pair_to_list (x)
(CONS (CAR x)
(CONS (CDR x) NIL)) )
(pair_to_list '(A B)) ; = (A B)
(DEFUN list_to_pair (x)
(CONS (CAR x) (CADR x)) )
(list_to_pair '(A B C)) ; = (A . B)
По этим определениям видно, что , т.е. на нее расходуется больше памяти.
Следующие функции полезны, когда рассматриваются лишь списки.
x и y, сцепляющая два списка в один
(DEFUN append (x y)
(COND
((null x) y)
((QUOTE T)
(CONS (CAR x)
(append (CDR x) y)
)
)
) )
(append '(A B) '(C D E)) ; = (A B C D E)
x и y, выясняющая, встречается ли S-выражение x среди элементов списка y
(DEFUN member (x y)
(COND
((null y) (QUOTE NIL) )
((equal x (CAR y)) (QUOTE T) )
((QUOTE T) (member x (CDR y)) )
) )
(member '(a) '(b (a) d)) ; = T
(member 'a '(b (a) d)) ; = NIL
PAIRLIS — функция аргументов x, y, al строит список пар соответствующих элементов из списков x и y и присоединяет их к списку al. Полученный список пар, похожий на таблицу с двумя столбцами, называется
(DEFUN pairlis (x y al)
(COND
((null x) al)
((QUOTE T) (CONS
(CONS (CAR x)(CAR Y) )
(pairlis (CDR x)(CDR y)al)
) )
) )
(pairlis '(A B C)
'(u t v)
'((D . y)(E . y)) )
; = ((C . v)(B . t)( A . u) (D . y)(E . y))
ASSOC — функция двух аргументов, x и al. Если al — ассоциативный список, подобный тому, что формирует функция pairlis, то assoc выбирает из него первую пару, начинающуюся с x. Таким образом, это функция поиска определения или значения по таблице, реализованной в форме
(DEFUN assoc (x al)
(COND
((equal x (CAAR al)) (CAR al) )
((QUOTE T) (assoc x (CDR al)) )
) )
Частичная функция — рассчитана на наличие ассоциации.
(assoc 'B '((A . (m n))
(B . (CAR x))
(C . w)
(B . (QUOTE T)) )
)
; = (B . (CAR x))
SUBLIS — функция двух аргументов al и y, предполагается, что первый из аргументов AL устроен как ((u1 . v1) ... (uK . vK)), где u есть атомы, а второй аргумент Y — любое S-выражение. Действие sublis заключается в обработке Y, такой, что вхождения переменных Ui, связанные в Vi, заменяются на эти значения. Другими словами в S-выражении Y вхождения переменных U заменяются на соответствующие им V из списка пар AL. Вводим вспомогательную функцию SUB2, обрабатывающую атомарные S-выражения, а затем — полное определение SUBLIS:
(DEFUN sub2 (al z)
(COND
((null al) z)
((equal (CAAR al) z) (CDAR al) )
((QUOTE T) (sub2 (CDR al) z) )
) )
(DEFUN sublis (al y)
(COND
((ATOM y) (sub2 al y))
((QUOTE T)(CONS
(sublis al (CAR y))
(sublis al (CDR y))
) ) ) )
(sublis '((x . Шекспир)
(y . (Ромео и Джульетта)) )
'(x написал трагедию y) )
; = (Шекспир написал трагедию (Ромео и Джульетта))
z перед вхождением ключа x в список al
(DEFUN insert (al x z)
(COND
((null al) NIL)
((equal (CAR al) x) (CONS z al) )
((QUOTE T) (CONS (CAR al)
(insert (CDR al) x z) ))
) )
(insert '(a b c) 'b 's) = (a s b c)
ASSIGN — модель присваивания переменным, хранящим значения в
(DEFUN assign (x v al)
(COND
((Null al) (CONS(CONS x v) NIL ) )
((equal x (CAAR al)) (CONS(CONS x v)
(CDR al)) )
((QUOTE T) (CONS (CAR al)
(assign x v (CDR al)) ))
)
)
(assign 'a 111 '((a . 1)(b . 2)(a . 3)))
; = ((a . 111)(b . 2)(a . 3))
(assign 'a 111 '((c . 1)(b . 2)(a . 3)))
; = ((c . 1)(b . 2)(a . 111))
(assign 'a 111 '((c . 1)(d . 3)))
; = ((c . 1)(d . 3) (a . 111))
(DEFUN reverse (m)
(COND ((null m) NIL)
(T (append(reverse(CDR m))
(list(CAR m)) ))
) )
(DEFUN reverse (m) (rev m NIL))
(DEFUN rev (m n)
(COND ((null m)N)
(T (rev(CDR m)
(CONS (CAR m) n))
) ) )
EVAL, которую предстоит определить, должна удовлетворять следующему условию: если представленная аргументом форма сводится к вычислению функции, имеющей значение на списке аргументов из этой же формы, то данное значение и является результатом функции eval.
(EVAL '(fn arg1 ... argK)) ; = результат применения fn к аргументам arg1, ..., argK.
Явное определение
(EVAL '((LAMBDA (x y) (CONS (CAR x) y))
'(A B) '(C D) ))
; = (A C D)
Вводим две важные функции EVAL-А и APPLY для обработки форм и
Сначала этот список пуст.
Вернемся к синтаксической сводке вычислимых форм.
форма ::= переменная
| (QUOTE S-выражение)
| (COND (форма форма) ... (форма форма))
| (функция аргумент ...)
аргумент ::= форма
переменная ::= идентификатор
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
идентификатор ::= атом
Ветвям этой сводки будут соответствовать ветви универсальной функции:
Кроме того работа с идентификаторами использует ассоциативный список для хранения связанных имен - значений переменных и определений функций.
(DEFUN EVAL (e) (eval-a e '((NIL . NIL)(T . T))))
Вспомогательная функция APPLY понадобилась для выделения EVAL-A понадобилась, чтобы для EVAL завести накапливающий параметр — (( обеспечивает, что атомы
(DEFUN eval-a(e a)
(COND
((ATOM e) (CDR(assoc e a)) )
((EQ (CAR e) 'QUOTE) (cadr e))
((EQ (CAR e) 'COND) (evcon (CDR e) a))
( T (apply (CAR e) (evlis (CDR e) a) a) )
) )
(defun apply (fn x a)
(COND
((ATOM fn)
(COND
((EQ fn 'CAR) (caar x))
((EQ fn 'CDR) (cdar x))
((EQ fn 'CONS) (CONS (CAR x)(cadr x)) )
((EQ fn 'ATOM) (ATOM (CAR x)) )
((EQ fn 'EQ) (EQ (CAR x)(cadr x)) )
(T (apply (eval-a fn a) x a))
) )
((EQ (CAR fn)'LAMBDA) (eval-a (caddr fn)
(pairlis (cadr fn) x a) ))
((EQ (CAR fn) 'LABEL) (apply (caddr fn) x
(CONS(CONS(cadr fn) (caddr fn)) a)
) ) ) )
ASSOC и PAIRLIS уже определены ранее.
(DEFUN evcon (c a)
(COND
((eval-a (caar c) a) (eval-a (cadar c) a) )
( T (evcon (CDR c) a) )
) )
(Не допускается отсутствие истинного предиката, т.е. пустого C.)
(DEFUN evlis (m a)
(COND
((null m) NIL )
( T (CONS(eval-a (CAR m) a)
(evlis(CDR m) a)
) ) ) )
При
(DEFUN EVAL (e) (eval-a e ObList ))
определения функций могут накапливаться в системной переменной ObList, то есть работать как глобальные определения. ObList обязательно должна содержать глобальное определение встроенной константы ", можно и сразу разместить в ней константу "T", выполняющую роль значения "истина".
Поясним ряд пунктов этих определений.
Аргумент EVAL — форма. Если она — атом, то этот атом может быть только именем переменной, а значение переменной должно уже находиться в ассоциативном списке.
Если CAR от формы — QUOTE, то она представляет собой константу, значение которой выделяется как CADR от нее самой.
Если CAR от формы — , то форма — условное выражение. Вводим вспомогательную функцию EVAL для дальнейших вычислений.
Все остальные случаи рассматриваются как список из функции с аргументами, который обрабатывается функцией APPLY.
Вспомогательная функция
Первый аргумент (CAR . В таком случае соответствующая ветвь вычисляет значение этой функции на заданных аргументах. В противном случае, этот атом — название ранее заданного определения функции. Определение можно найти в
Если функция начинается с LAMBDA, то ее аргументы попарно соединяются со связанными переменными, а тело определения (форма из лямбда-выражения) передается как аргумент функции EVAL-A для дальнейшей обработки.
Если функция начинается с LABEL, то ее название и определение соединяются в пару, и полученная пара размещается в ассоциативном списке, чтобы имя функции стало определенным при дальнейших вычислениях. Они произойдут как
Определение
EQ всегда имеет значение, но смысл его на неатомарных аргументах будет более ясен после знакомства со структурами данных, используемыми для представления списков в машине.CAR и CDR не определены для атомарных аргументов. Такие функции, имеющие осмысленный результат не на всех значениях естественной области определения, называют частичными. Отладка и применение частичных функций требует большего контроля, чем работа с ERROR, символизирующим исключительные ситуации.COND выбрана для начального знакомства как наиболее общая. За редким исключением в (QUOTE T) или (QUOTE NIL ). Вместо них используются встроенные константы T и NIL , соответственно.Приведенное выше самоопределение Лисп-интерпретации является концептуальным минимумом, обеспечивающим постепенность восприятия более сложных особенностей специфики функционального программирования, а также методов реализации языков и систем программирования, которые будут иллюстрироваться в дальнейшем. Они будут введены как расширения или уточнения чистого определения
Хотя формальное правило записи программ вычислений в виде S-выражения предписывает, что константа Т — это (QUOTE T), было оговорено, что в системе всегда пишется Т. Кроме того, оказался удобнее, чем атом F, встречавшийся в начальных предложениях по Лиспу аналог значения FALSE. Программист может либо принять это правило на веру, либо изучить следующие уточнения.
В T и . Данные символы — действительные значения всех предикатов в системе. Главная причина в удобстве кодирования. Во многих случаях достаточно отличать произвольное значение от пустого списка. Если атомы T и F имеют значение T и , соответственно, то символы T и F в качестве константных предикатов могут работать, потому что:
(eval-a T '((NIL . NIL)(T . T) (F . NIL))) ; = T (eval-a NIL'((NIL . NIL)(T . T) (F . NIL))) ; = NIL (eval-a F '((NIL . NIL)(T . T) (F . NIL))) ; = NIL
Формы (QUOTE T) и (QUOTE будут также работать, потому что:
(EVAL (QUOTE T) ) ; = T (EVAL (QUOTE NIL) ) ; = NIL
Но
(EVAL (QUOTE F)NIL) ; = F
Это неправильно, отлично от , и поэтому (QUOTE F) не будет работать как представление ложного значения в системе.
Заметим, что
(EVAL T ) ; = T (EVAL NIL ) ; = NIL (EVAL F) ; = NIL
будет работать в силу причин, которые объясняются в лекции 6.
Формального различия между функцией и предикатом в T либо . Это верно для всех предикатов системы. Можно использовать форму, не являющуюся предикатом там, где требуется предикат: предикатная позиция условного выражения или аргумент логической операции. Семантически любое S-выражение, отличное от , будет рассматриваться в таком случае как истинное. Первое следствие из этого — предикат NOT идентичны. Второе — то, что (QUOTE T) или (QUOTE Х) практически Т как константные предикаты.
Предикат EQ ведет себя следующим образом:
EQ является NIL .Т.T или NIL в зависимости от того, идентично ли представление аргументов в памяти.EQ всегда T или NIL . Оно никогда не бывает не определено, даже если аргументы неправильные.Более интересные и не столь очевидные следствия возникают при расширении этой формальной системы, что и будет продемонстрировано в следующих лекциях.
Приведенные ранее описания и правила записи функций и выражений в этой лекции получат более
строгое определение. Начнем с синтаксического
Синтаксис данных в
атом ::= БУКВА конец_атома
Это правило констатирует, что атомы начинаются с буквы.
конец_атома ::= пусто
| БУКВА конец_атома
| цифра конец_атома
Это правило констатирует, что после первой литеры в изображении атома могут быть как буквы, так и цифры.
В
S-выражение ::= атом
| (S-выражение . S-выражение)
| (S-выражение ... )
Данное правило констатирует, что S-выражения — это или атомы, или узлы из пары S-выражений, или списки из S-выражений. (Три точки означают, что допустимо любое число вхождений предшествующего вида объектов, включая ни одного.)
Согласно такому правилу "()" есть допустимое S-выражение. Оно в языке .
Базовая система представления данных — точечная нотация, хотя на практике запись в виде списков удобнее.
Любой список можно представить
() = NIL (a . NIL) = (a) - - - (a1 . ( ... (aK . NIL) ... )) = (a1 ... aK)
Такая единая структура данных оказалась вполне достаточной для представления сколь угодно
сложных программ. Дальнейшее определение языка
Другие правила представления данных нужны лишь при расширении и специализации лексики языка (числа, строки, имена особого вида и т.п.). Они не влияют ни на общий синтаксис языка, ни на строй его понятий, а лишь характеризуют разнообразие сферы его конкретных приложений.
Синтаксис программ является конкретизацией синтаксиса данных, а именно — выделением из класса
S-выражений подкласса вычислимых выражений (форм), т.е. данных, имеющих смысл как выражения языка
и приспособленных к вычислению. Внешне это выглядит как объявление объектов, заранее известных в языке, и
представление разных форм,
Выполнение программы устроено как интерпретация данных, представляющих выражения, имеющие значение.
Ниже приведены синтаксические правила для обычных конструкций, к которым относятся
идентификатор ::= атом
Идентификатор — это подкласс атомов, используемых при именовании неоднократно используемых объектов программы — функций и переменных. Предполагается, что идентифицируемые объекты размещаются в памяти так, что по идентификатору их можно найти.
Понятие "идентификатор" выделено для того, чтобы по мере развития определения атома не требовалось
на все виды атомов искусственно распространять
форма ::= константа
| переменная
| (функция аргумент ... )
| (COND (форма форма) (форма форма) ... )
константа ::= (QUOTE S-выражение)
| 'S-выражение
переменная ::= идентификатор
Переменная — это подкласс идентификаторов, которым сопоставлено многократно используемое значение, ранее вычисленное в подходящем контексте. Подразумевается, что одна и та же переменная в разных контекстах может иметь разные значения.
Таким образом, класс форм — это объединение класса переменных и подкласса списков,
начинающихся с QUOTE, или с представления некоторой функции.
аргумент ::= форма
Форма — это выражение, которое может быть QUOTE, блокирующей вычисление. Представление
констант с помощью QUOTE устанавливает границу, далее которой вычисление не идет.
Использование апострофа "'" — просто сокращенное обозначение для удобства набора внешних форм.
Константные значения аргументов характерны при тестировании и демонстрации программ.
Если форма представляет собой переменную, то ее значением должно быть S-выражение, связанное с
этой переменной до момента
Третья ветвь определения гласит, что можно написать функцию, затем перечислить ее аргументы, и все это как общий список заключить в скобки.
Аргументы представляются формами. Это означает, что допустимы композиции функций.
Обычно аргументы вычисляются в порядке вхождения в
Последняя ветвь определяет формат условного выражения. Согласно этому формату условное выражение
строится из размещенных в двухэлементном списке синтаксически различимых позиций
для пропозициональных термов и обычных форм. Двухэлементные списки из определения
условного выражения рассматриваются как представление предиката и соответствующего ему S-выражения.
Значение условного выражения определяется перебором предикатов по порядку, пока не
найдется форма, значение которой отлично от , что означает логическое значение "истина".
Строго говоря, такая форма должна быть найдена непременно. Тогда вычисляется S-выражение, размещенное
вторым элементом этого же двухэлементного списка. Остальные предикаты и формы условного выражения не
вычисляют (логика Маккарти), их формальная корректность или определенность не влияют на
существование результата.
Разница между пропозициональными и обычными формами заключается лишь в трактовке их результатов. Любая форма может играть роль предиката.
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
Название — это подкласс идентификаторов, определение которых хранится в памяти, но оно может не подвергаться влиянию контекста вычислений.
Таким образом, класс функций — это объединение класса назва-ний и подкласса трехэлементных списков, начинающихся с LAMBDA или LABEL.
Функция может быть представлена просто именем. В таком случае ее смысл должен быть заранее известен. Функция может быть введена с помощью лямбда-выражения, устанавливающего соответствие между аргументами функции и связанными переменными, упоминаемыми в теле ее определения (в определяющей ее форме). Форма из определения функции может включать переменные, не включенные в лямбда-список, — так называемые свободные переменные. Их значения должны устанавливаться на более внешнем уровне. Если функция рекурсивна, то следует объявить ее имя с помощью специальной функции LABEL. (Используемая в примерах , по существу, совмещает эффекты LABEL и LAMBDA.)
форма ::= переменная
| (QUOTE S-выражение)
| (COND (форма форма) ... (форма форма))
| (функция аргумент ... )
аргумент ::= форма
переменная ::= идентификатор
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
идентификатор ::= атом
S-выражение ::= атом
| (S-выражение . S-выражение)
| (S-выражение ...)
атом ::= БУКВА конец_атома
конец_атома ::= пусто
| БУКВА конец_атома
| цифра конец_атома
Интерпретация или
Определим eval от аргумента expr — выражения, являющегося произвольной вычислимой формой языка
Универсальная функция должна предусматривать основные виды вычисляемых форм, задающих значения аргументов, а также представления функций, в соответствии со сводом приведенных выше правил языка. При
x, elem, смысл которых зависит от контекста, в котором они вычисляются;QUOTE, можно просто извлечь из списка ее аргументов. Например, значением константы (QUOTE T) является атом T, обычно символизирующий значение "истина";(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
)
должна обеспечивать выбор ветви в зависимости от атомарности значения аргумента. Семантика NIL . Иногда это придает условным выражениям лаконичность;(first (CAR x)) внутренняя функция CAR сначала получит в качестве своего аргумента значение переменной x, а потом свой результат передаст как аргумент более first ;CAR, CDR , CONS и т.п., и имена функций, введенных в программе, например first. Для встроенных функций (LAMBDA (x)
(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
) )
зависит от одного аргумента, значение которого должно быть связано с переменной x. В определении используется first, которая должна быть определена в более внешнем контексте;LABEL, то понадобится сохранить имя функции с соответствующим ее определением так, чтобы корректно выполнялись рекурсивные вызовы функции. Например, предыдущее LAMBDA-определение LABEL, первый аргумент которой — fisrt, (LABEL first
(LAMBDA (x)
(COND ((ATOM x) x)
((QUOTE T) (first (CAR x)) )
) ) )
Таким образом,
cons , car, cdr , atom , eq );lambda, label );quote, cond , eval ).В большинстве языков программирования аналоги первых двух подсистем нацелены на обработку элементарных данных и конструирование составных значений, кроме того, иначе установлены границы между подсистемами.
Прежде чем дать определение
Начнем с общих методов обработки S-выражений.
(DEFUN among (x y)
(COND
((ATOM y) (EQ x y))
((among x (CAR y)) (QUOTE T))
((QUOTE T) (among x (CDR y) ))
) )
(among 'A '(C (A B))) ; = T
(among 'A '(C D B)) ; = NIL
Символ " ; " - начало примечания (до конца строки).
EQUAL — предикат, проверяющий равенство двух S-выражений. Его значение "истина" для идентичных аргументов и "ложь" для различных. (Элементарный предикат EQ определен только для атомов.) Определение EQUAL иллюстрирует условное выражение внутри условного выражения (двухуровневое условное выражение и equalнаправленная рекурсия).
(DEFUN equal (x y)
(COND
((ATOM x) (COND
((ATOM y) (EQ x y))
((QUOTE T) (QUOTE NIL))
) )
((equal (CAR x)(CAR y))
(equal (CDR x)(CDR y)) )
((QUOTE T) (QUOTE NIL) )
) )
(equal '(A (B)) '(A (B))) ; = T
(equal '(A B) '(A . B)) ; = NIL
x, y, z, строящая результат замены S-выражением x всех вхождений y в S-выражение z.
(DEFUN subst (x y z)
(COND
((equal y z) x)
((ATOM z) z)
((QUOTE T)(CONS
(subst x y (CAR z))
(subst x y (CDR z))
)
)
) )
(subst '(x . A) 'B '((A . B) . C)) = ((A x . A) . C)
Использование equal в этом определении позволяет осуществлять
(subst 'x '(B C D) '((A B C D)(E B C D)(F B C D)))
; = ((A . x) (E . x) (F . x))
(DEFUN null (x)
(COND
((EQ x (QUOTE NIL)) (QUOTE T))
((QUOTE T) (QUOTE NIL))
) )
При необходимости можно компоненты точечной пары разместить в двухэлементном списке функцией PAIR_TO_LIST, и наоборот, из первых двух элементов списка построить точечную
(DEFUN pair_to_list (x)
(CONS (CAR x)
(CONS (CDR x) NIL)) )
(pair_to_list '(A B)) ; = (A B)
(DEFUN list_to_pair (x)
(CONS (CAR x) (CADR x)) )
(list_to_pair '(A B C)) ; = (A . B)
По этим определениям видно, что , т.е. на нее расходуется больше памяти.
Следующие функции полезны, когда рассматриваются лишь списки.
x и y, сцепляющая два списка в один
(DEFUN append (x y)
(COND
((null x) y)
((QUOTE T)
(CONS (CAR x)
(append (CDR x) y)
)
)
) )
(append '(A B) '(C D E)) ; = (A B C D E)
x и y, выясняющая, встречается ли S-выражение x среди элементов списка y
(DEFUN member (x y)
(COND
((null y) (QUOTE NIL) )
((equal x (CAR y)) (QUOTE T) )
((QUOTE T) (member x (CDR y)) )
) )
(member '(a) '(b (a) d)) ; = T
(member 'a '(b (a) d)) ; = NIL
PAIRLIS — функция аргументов x, y, al строит список пар соответствующих элементов из списков x и y и присоединяет их к списку al. Полученный список пар, похожий на таблицу с двумя столбцами, называется
(DEFUN pairlis (x y al)
(COND
((null x) al)
((QUOTE T) (CONS
(CONS (CAR x)(CAR Y) )
(pairlis (CDR x)(CDR y)al)
) )
) )
(pairlis '(A B C)
'(u t v)
'((D . y)(E . y)) )
; = ((C . v)(B . t)( A . u) (D . y)(E . y))
ASSOC — функция двух аргументов, x и al. Если al — ассоциативный список, подобный тому, что формирует функция pairlis, то assoc выбирает из него первую пару, начинающуюся с x. Таким образом, это функция поиска определения или значения по таблице, реализованной в форме
(DEFUN assoc (x al)
(COND
((equal x (CAAR al)) (CAR al) )
((QUOTE T) (assoc x (CDR al)) )
) )
Частичная функция — рассчитана на наличие ассоциации.
(assoc 'B '((A . (m n))
(B . (CAR x))
(C . w)
(B . (QUOTE T)) )
)
; = (B . (CAR x))
SUBLIS — функция двух аргументов al и y, предполагается, что первый из аргументов AL устроен как ((u1 . v1) ... (uK . vK)), где u есть атомы, а второй аргумент Y — любое S-выражение. Действие sublis заключается в обработке Y, такой, что вхождения переменных Ui, связанные в Vi, заменяются на эти значения. Другими словами в S-выражении Y вхождения переменных U заменяются на соответствующие им V из списка пар AL. Вводим вспомогательную функцию SUB2, обрабатывающую атомарные S-выражения, а затем — полное определение SUBLIS:
(DEFUN sub2 (al z)
(COND
((null al) z)
((equal (CAAR al) z) (CDAR al) )
((QUOTE T) (sub2 (CDR al) z) )
) )
(DEFUN sublis (al y)
(COND
((ATOM y) (sub2 al y))
((QUOTE T)(CONS
(sublis al (CAR y))
(sublis al (CDR y))
) ) ) )
(sublis '((x . Шекспир)
(y . (Ромео и Джульетта)) )
'(x написал трагедию y) )
; = (Шекспир написал трагедию (Ромео и Джульетта))
z перед вхождением ключа x в список al
(DEFUN insert (al x z)
(COND
((null al) NIL)
((equal (CAR al) x) (CONS z al) )
((QUOTE T) (CONS (CAR al)
(insert (CDR al) x z) ))
) )
(insert '(a b c) 'b 's) = (a s b c)
ASSIGN — модель присваивания переменным, хранящим значения в
(DEFUN assign (x v al)
(COND
((Null al) (CONS(CONS x v) NIL ) )
((equal x (CAAR al)) (CONS(CONS x v)
(CDR al)) )
((QUOTE T) (CONS (CAR al)
(assign x v (CDR al)) ))
)
)
(assign 'a 111 '((a . 1)(b . 2)(a . 3)))
; = ((a . 111)(b . 2)(a . 3))
(assign 'a 111 '((c . 1)(b . 2)(a . 3)))
; = ((c . 1)(b . 2)(a . 111))
(assign 'a 111 '((c . 1)(d . 3)))
; = ((c . 1)(d . 3) (a . 111))
(DEFUN reverse (m)
(COND ((null m) NIL)
(T (append(reverse(CDR m))
(list(CAR m)) ))
) )
(DEFUN reverse (m) (rev m NIL))
(DEFUN rev (m n)
(COND ((null m)N)
(T (rev(CDR m)
(CONS (CAR m) n))
) ) )
EVAL, которую предстоит определить, должна удовлетворять следующему условию: если представленная аргументом форма сводится к вычислению функции, имеющей значение на списке аргументов из этой же формы, то данное значение и является результатом функции eval.
(EVAL '(fn arg1 ... argK)) ; = результат применения fn к аргументам arg1, ..., argK.
Явное определение
(EVAL '((LAMBDA (x y) (CONS (CAR x) y))
'(A B) '(C D) ))
; = (A C D)
Вводим две важные функции EVAL-А и APPLY для обработки форм и
Сначала этот список пуст.
Вернемся к синтаксической сводке вычислимых форм.
форма ::= переменная
| (QUOTE S-выражение)
| (COND (форма форма) ... (форма форма))
| (функция аргумент ...)
аргумент ::= форма
переменная ::= идентификатор
функция ::= название
| (LAMBDA список_переменных форма)
| (LABEL название функция)
список_переменных ::= (переменная ... )
название ::= идентификатор
идентификатор ::= атом
Ветвям этой сводки будут соответствовать ветви универсальной функции:
Кроме того работа с идентификаторами использует ассоциативный список для хранения связанных имен - значений переменных и определений функций.
(DEFUN EVAL (e) (eval-a e '((NIL . NIL)(T . T))))
Вспомогательная функция APPLY понадобилась для выделения EVAL-A понадобилась, чтобы для EVAL завести накапливающий параметр — (( обеспечивает, что атомы
(DEFUN eval-a(e a)
(COND
((ATOM e) (CDR(assoc e a)) )
((EQ (CAR e) 'QUOTE) (cadr e))
((EQ (CAR e) 'COND) (evcon (CDR e) a))
( T (apply (CAR e) (evlis (CDR e) a) a) )
) )
(defun apply (fn x a)
(COND
((ATOM fn)
(COND
((EQ fn 'CAR) (caar x))
((EQ fn 'CDR) (cdar x))
((EQ fn 'CONS) (CONS (CAR x)(cadr x)) )
((EQ fn 'ATOM) (ATOM (CAR x)) )
((EQ fn 'EQ) (EQ (CAR x)(cadr x)) )
(T (apply (eval-a fn a) x a))
) )
((EQ (CAR fn)'LAMBDA) (eval-a (caddr fn)
(pairlis (cadr fn) x a) ))
((EQ (CAR fn) 'LABEL) (apply (caddr fn) x
(CONS(CONS(cadr fn) (caddr fn)) a)
) ) ) )
ASSOC и PAIRLIS уже определены ранее.
(DEFUN evcon (c a)
(COND
((eval-a (caar c) a) (eval-a (cadar c) a) )
( T (evcon (CDR c) a) )
) )
(Не допускается отсутствие истинного предиката, т.е. пустого C.)
(DEFUN evlis (m a)
(COND
((null m) NIL )
( T (CONS(eval-a (CAR m) a)
(evlis(CDR m) a)
) ) ) )
При
(DEFUN EVAL (e) (eval-a e ObList ))
определения функций могут накапливаться в системной переменной ObList, то есть работать как глобальные определения. ObList обязательно должна содержать глобальное определение встроенной константы ", можно и сразу разместить в ней константу "T", выполняющую роль значения "истина".
Поясним ряд пунктов этих определений.
Аргумент EVAL — форма. Если она — атом, то этот атом может быть только именем переменной, а значение переменной должно уже находиться в ассоциативном списке.
Если CAR от формы — QUOTE, то она представляет собой константу, значение которой выделяется как CADR от нее самой.
Если CAR от формы — , то форма — условное выражение. Вводим вспомогательную функцию EVAL для дальнейших вычислений.
Все остальные случаи рассматриваются как список из функции с аргументами, который обрабатывается функцией APPLY.
Вспомогательная функция
Первый аргумент (CAR . В таком случае соответствующая ветвь вычисляет значение этой функции на заданных аргументах. В противном случае, этот атом — название ранее заданного определения функции. Определение можно найти в
Если функция начинается с LAMBDA, то ее аргументы попарно соединяются со связанными переменными, а тело определения (форма из лямбда-выражения) передается как аргумент функции EVAL-A для дальнейшей обработки.
Если функция начинается с LABEL, то ее название и определение соединяются в пару, и полученная пара размещается в ассоциативном списке, чтобы имя функции стало определенным при дальнейших вычислениях. Они произойдут как
Определение
EQ всегда имеет значение, но смысл его на неатомарных аргументах будет более ясен после знакомства со структурами данных, используемыми для представления списков в машине.CAR и CDR не определены для атомарных аргументов. Такие функции, имеющие осмысленный результат не на всех значениях естественной области определения, называют частичными. Отладка и применение частичных функций требует большего контроля, чем работа с ERROR, символизирующим исключительные ситуации.COND выбрана для начального знакомства как наиболее общая. За редким исключением в (QUOTE T) или (QUOTE NIL ). Вместо них используются встроенные константы T и NIL , соответственно.Приведенное выше самоопределение Лисп-интерпретации является концептуальным минимумом, обеспечивающим постепенность восприятия более сложных особенностей специфики функционального программирования, а также методов реализации языков и систем программирования, которые будут иллюстрироваться в дальнейшем. Они будут введены как расширения или уточнения чистого определения
Хотя формальное правило записи программ вычислений в виде S-выражения предписывает, что константа Т — это (QUOTE T), было оговорено, что в системе всегда пишется Т. Кроме того, оказался удобнее, чем атом F, встречавшийся в начальных предложениях по Лиспу аналог значения FALSE. Программист может либо принять это правило на веру, либо изучить следующие уточнения.
В T и . Данные символы — действительные значения всех предикатов в системе. Главная причина в удобстве кодирования. Во многих случаях достаточно отличать произвольное значение от пустого списка. Если атомы T и F имеют значение T и , соответственно, то символы T и F в качестве константных предикатов могут работать, потому что:
(eval-a T '((NIL . NIL)(T . T) (F . NIL))) ; = T (eval-a NIL'((NIL . NIL)(T . T) (F . NIL))) ; = NIL (eval-a F '((NIL . NIL)(T . T) (F . NIL))) ; = NIL
Формы (QUOTE T) и (QUOTE будут также работать, потому что:
(EVAL (QUOTE T) ) ; = T (EVAL (QUOTE NIL) ) ; = NIL
Но
(EVAL (QUOTE F)NIL) ; = F
Это неправильно, отлично от , и поэтому (QUOTE F) не будет работать как представление ложного значения в системе.
Заметим, что
(EVAL T ) ; = T (EVAL NIL ) ; = NIL (EVAL F) ; = NIL
будет работать в силу причин, которые объясняются в лекции 6.
Формального различия между функцией и предикатом в T либо . Это верно для всех предикатов системы. Можно использовать форму, не являющуюся предикатом там, где требуется предикат: предикатная позиция условного выражения или аргумент логической операции. Семантически любое S-выражение, отличное от , будет рассматриваться в таком случае как истинное. Первое следствие из этого — предикат NOT идентичны. Второе — то, что (QUOTE T) или (QUOTE Х) практически Т как константные предикаты.
Предикат EQ ведет себя следующим образом:
EQ является NIL .Т.T или NIL в зависимости от того, идентично ли представление аргументов в памяти.EQ всегда T или NIL . Оно никогда не бывает не определено, даже если аргументы неправильные.Более интересные и не столь очевидные следствия возникают при расширении этой формальной системы, что и будет продемонстрировано в следующих лекциях.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.