Интерпретация или
Определим универсальную функцию eval от аргумента - выражения, являющегося произвольной вычислимой формой языка Лисп.
x ", " elem ", смысл которых зависит от контекста, в котором они вычисляются.QUOTE, можно просто извлечь из списка ее аргументов. Например, значением константы (QUOTE T) является атом T, обычно символизирующий значение "истина".(COND ((ATOM x) x) ((QUOTE T) (first (CAR x) )) )
должна обеспечивать выбор ветви в зависимости от атомарности значения аргумента. Семантика идеального Лиспа не определяет значение условного выражения при отсутствии предиката со значением "истина".
(first (CAR x)) внутренняя функция CAR сначала получит в качестве своего аргумента значение переменной x, а потом свой результат передаст как аргумент более внешней функции first.CAR, CDR, CONS и т.п., и имена функций, введенных в программе, например, first. Для встроенных функций интерпретатор сам знает как найти их значение по заданным аргументам, а для введенных в программе функций - использует их определение, которое находит по имени или по контексту.(LAMBDA (x) (COND ((ATOM x) x)
((QUOTE T) (first (CAR x) )) ))
зависит от одного аргумента, значение которого должно быть связано с переменной x. В определении используется свободная first, которая должна быть определена в более внешнем контексте.
DEFUN, то понадобится сохранить имя функции с соответствующим ее определением так, чтобы корректно выполнялись рекурсивные вызовы функции. Например, предыдущее LAMBDA -определение DEFUN, первый аргумент которой – fisrt - (DEFUN first (x) (COND ((ATOM x) x) ((QUOTE T) (first (CAR x) )) ))
Можно сказать, что DEFUN замыкает выражение, содержащее функциональную переменную.
Таким образом, интерпретация функций осуществляется как взаимодействие четырех подсистем:
cons, car, cdr, atom, eq ),lambda, defun ),quote, cond, eval ).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 <список_переменных> <форма>)
| (DEFUN <название> <функция>)
<список_переменных> ::= (<переменная> ... )
<название> = <идентификатор>
<идентификатор> ::= <атом>
Каждой ветви этой сводки соответствует ветвь универсальной функции:
(DEFUN eval (e) (ev e '((Nil . Nil))))
Вспомогательная функция ev понадобилась, чтобы ввести накапливающий параметр –
(defun ev (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) )) )
Поясним ряд пунктов этого определения.
Первый аргумент ev - форма. Если она - атом, то этот атом может быть только именем переменной, а значение переменной должно бы уже находиться в ассоциативном списке.
Если CAR от формы - QUOTE, то она представляет собой константу, значение которой вычисляется как CADR от нее самой.
Если CAR от формы - COND, то форма - условное выражение. Вводим вспомогательную функцию , (определение ее будет дано ниже), которая обеспечивает вычисление предикатов (пропозициональных термов) по порядку и выбор формы, соответствующей первому предикату, принимающему значение "истина". Эта форма передается EV для дальнейших вычислений.
Все остальные случаи рассматриваются как список из функции с последующими аргументами.
Вспомогательная функция обеспечивает вычисление аргументов, затем представление функции и список вычисленных значений аргументов передаются функции APPLY.
(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)) )
((QUOTE T) (apply (ev fn a) x a)) ) )
)
((eq(car fn)'LAMBDA) (ev (caddr fn) (pairlis (cadr fn) x a) ))
((eq (car fn) 'DEFUN) (apply (cadddr fn) x (cons (cons (cadr fn)
(cons 'LAMBDA (caddr fn) ) ) a) ))))
Первый аргумент apply - функция. Если она - атом, то существует две возможности: атом представляет одну из элементарных функций ( car cdr cons atom eq ). В таком случае соответствующая ветвь вычисляет значение этой функции на заданных аргументах. В противном случае, этот атом - имя ранее заданного определения, которое можно найти в ассоциативном списке.
Если функция начинается с LAMBDA, то ее аргументы попарно соединяются со связанными переменными, а тело определения (форма из лямбда-выражения) передается как аргумент функции EV для дальнейшей обработки.
Если функция начинается с DEFUN, то ее название и определение соединяются в пару и полученная пара размещается в ассоциативном списке, чтобы имя функции стало определенным при дальнейших вычислениях. Они произойдут как рекурсивный вызов apply, которая вместо имени функции теперь работает с ее определением при более полном ассоциативном списке - в нем теперь размещено определение названия функции. Поскольку определение размещается на "верху" стека, оно становится доступным для всех последующих переопределений, то есть работает как локальный объект. Глобальные объекты, такие как обеспечивает DEFUN в системе , устроены немного иначе, что будет рассмотрено в следующей лекции.
Упражнение 6.1: Это определение можно немного уточнить, если а-список при связывании названий функций пополнять не в начале, а в конце.
assoc и pairlis уже определены ранее.
(DEFUN evcon (c a) (COND
((ev (caar c) a) (ev (cadar c) a) )
( T (evcon (cdr c) a) ) ))
*) Примечание. В идеальном Лиспе не допускается отсутствие истинного предиката, т.е. пустого C.
(DEFUN evlis (m a) (COND
((null m) Nil )
( T (cons(ev (car m) a)
(evlis(cdr m) a) )) )
При
(DEFUN eval (e) (ev e ObList ))
определения функций могут накапливаться в системной переменной ObList, тогда они могут работать как глобальные определения. ObList обязательно должна содержать глобальное определение встроенной константы Nil, можно разместить в ней и представление истины - T.
Определение универсальной функции является важным шагом, показывающим одновременно и механизмы реализации языков программирования, и технику функционального программирования на любом языке. Пока еще не описаны многие другие особенности языка Лисп, которые будут рассмотрены позднее. Но все они будут увязаны в единую картину, основа которой согласуется с этим определением.
CAR и CDR не определены для атомарных аргументов. Такие функции, имеющие осмысленный результат не на всех значениях естественной области определения, называют частичными. Отладка и применение частичных функций требует большего контроля, чем работа с тотальными, всюду определенными функциями.Во многих Лисп-системах все элементарные функции вырабатывают результат и на списках, и на атомах, но его смысл зависит от системных решений, что может создавать трудности при переносе программ на другие системы. Базисный предикат EQ всегда имеет значение, но смысл его на неатомарных аргументах будет более понятен после знакомства со структурами данных, используемыми для представления списков в машине.
COND выбрана для начального знакомства как наиболее общая. За редким исключением в Лисп-системе нет необходимости писать в условных выражениях (QUOTE T) или (QUOTE NIL). Вместо них используются встроенные константы T и Nil соответственно.В Лиспе есть два атомных символа, которые представляют истину и ложь соответственно. Эти два атома - T и NIL. Эти символы - реальные значения всех предикатов в системе. Главная причина в удобстве кодирования. Во многих случаях достаточно отличать произвольное значение от пустого списка.
Не существует формального различия между функцией и предикатом в Лиспе. Предикат может быть определен как функция со значениями либо T либо NIL. Можно использовать форму, не являющуюся предикатом там, где требуется предикат: предикатная позиция условного выражения или аргумент логического предиката. Семантически любое S-выражение, только не NIL, будет рассматриватсья как истинное в таком случае. Предикат EQ ведет себя следующим образом:
EQ является NIL.Т.T или NIL в зависимости от того, идентично ли представление аргументов в памяти.EQ всегда T или NIL. Оно никогда не бывает неопределено, даже если аргументы плохие.Выполнено достаточно строгое построение совершенно формальной математической системы, называемой "Элементарный ЛИСП". Составляющие этой формальной системы:
Выполненное определение универсальной функции – макетный образец Лисп-системы, основные черты которой унаследованы многими системами программирования.
| (Apply Функция Список-аргументов ) | Применяет функцию к списку аргументов |
| ( Compile Название ) | Компилирует названную функцию, кроме того сообщает, успешна ли компиляция |
| (Eval Форма ) | Вычисление формы |
| (Funcall Функция Аргумент … ) | Применяет функцию к аргументам |
| (The Тип Форма) | Проверяет имеет ли аргумент указанный Тип |
| (Type-of Данное ) | Выдает тип данного |
| (Quote Форма ) | Форма без вычисления выдается как результат |
Интерпретация или
Определим универсальную функцию eval от аргумента - выражения, являющегося произвольной вычислимой формой языка Лисп.
x ", " elem ", смысл которых зависит от контекста, в котором они вычисляются.QUOTE, можно просто извлечь из списка ее аргументов. Например, значением константы (QUOTE T) является атом T, обычно символизирующий значение "истина".(COND ((ATOM x) x) ((QUOTE T) (first (CAR x) )) )
должна обеспечивать выбор ветви в зависимости от атомарности значения аргумента. Семантика идеального Лиспа не определяет значение условного выражения при отсутствии предиката со значением "истина".
(first (CAR x)) внутренняя функция CAR сначала получит в качестве своего аргумента значение переменной x, а потом свой результат передаст как аргумент более внешней функции first.CAR, CDR, CONS и т.п., и имена функций, введенных в программе, например, first. Для встроенных функций интерпретатор сам знает как найти их значение по заданным аргументам, а для введенных в программе функций - использует их определение, которое находит по имени или по контексту.(LAMBDA (x) (COND ((ATOM x) x)
((QUOTE T) (first (CAR x) )) ))
зависит от одного аргумента, значение которого должно быть связано с переменной x. В определении используется свободная first, которая должна быть определена в более внешнем контексте.
DEFUN, то понадобится сохранить имя функции с соответствующим ее определением так, чтобы корректно выполнялись рекурсивные вызовы функции. Например, предыдущее LAMBDA -определение DEFUN, первый аргумент которой – fisrt - (DEFUN first (x) (COND ((ATOM x) x) ((QUOTE T) (first (CAR x) )) ))
Можно сказать, что DEFUN замыкает выражение, содержащее функциональную переменную.
Таким образом, интерпретация функций осуществляется как взаимодействие четырех подсистем:
cons, car, cdr, atom, eq ),lambda, defun ),quote, cond, eval ).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 <список_переменных> <форма>)
| (DEFUN <название> <функция>)
<список_переменных> ::= (<переменная> ... )
<название> = <идентификатор>
<идентификатор> ::= <атом>
Каждой ветви этой сводки соответствует ветвь универсальной функции:
(DEFUN eval (e) (ev e '((Nil . Nil))))
Вспомогательная функция ev понадобилась, чтобы ввести накапливающий параметр –
(defun ev (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) )) )
Поясним ряд пунктов этого определения.
Первый аргумент ev - форма. Если она - атом, то этот атом может быть только именем переменной, а значение переменной должно бы уже находиться в ассоциативном списке.
Если CAR от формы - QUOTE, то она представляет собой константу, значение которой вычисляется как CADR от нее самой.
Если CAR от формы - COND, то форма - условное выражение. Вводим вспомогательную функцию , (определение ее будет дано ниже), которая обеспечивает вычисление предикатов (пропозициональных термов) по порядку и выбор формы, соответствующей первому предикату, принимающему значение "истина". Эта форма передается EV для дальнейших вычислений.
Все остальные случаи рассматриваются как список из функции с последующими аргументами.
Вспомогательная функция обеспечивает вычисление аргументов, затем представление функции и список вычисленных значений аргументов передаются функции APPLY.
(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)) )
((QUOTE T) (apply (ev fn a) x a)) ) )
)
((eq(car fn)'LAMBDA) (ev (caddr fn) (pairlis (cadr fn) x a) ))
((eq (car fn) 'DEFUN) (apply (cadddr fn) x (cons (cons (cadr fn)
(cons 'LAMBDA (caddr fn) ) ) a) ))))
Первый аргумент apply - функция. Если она - атом, то существует две возможности: атом представляет одну из элементарных функций ( car cdr cons atom eq ). В таком случае соответствующая ветвь вычисляет значение этой функции на заданных аргументах. В противном случае, этот атом - имя ранее заданного определения, которое можно найти в ассоциативном списке.
Если функция начинается с LAMBDA, то ее аргументы попарно соединяются со связанными переменными, а тело определения (форма из лямбда-выражения) передается как аргумент функции EV для дальнейшей обработки.
Если функция начинается с DEFUN, то ее название и определение соединяются в пару и полученная пара размещается в ассоциативном списке, чтобы имя функции стало определенным при дальнейших вычислениях. Они произойдут как рекурсивный вызов apply, которая вместо имени функции теперь работает с ее определением при более полном ассоциативном списке - в нем теперь размещено определение названия функции. Поскольку определение размещается на "верху" стека, оно становится доступным для всех последующих переопределений, то есть работает как локальный объект. Глобальные объекты, такие как обеспечивает DEFUN в системе , устроены немного иначе, что будет рассмотрено в следующей лекции.
Упражнение 6.1: Это определение можно немного уточнить, если а-список при связывании названий функций пополнять не в начале, а в конце.
assoc и pairlis уже определены ранее.
(DEFUN evcon (c a) (COND
((ev (caar c) a) (ev (cadar c) a) )
( T (evcon (cdr c) a) ) ))
*) Примечание. В идеальном Лиспе не допускается отсутствие истинного предиката, т.е. пустого C.
(DEFUN evlis (m a) (COND
((null m) Nil )
( T (cons(ev (car m) a)
(evlis(cdr m) a) )) )
При
(DEFUN eval (e) (ev e ObList ))
определения функций могут накапливаться в системной переменной ObList, тогда они могут работать как глобальные определения. ObList обязательно должна содержать глобальное определение встроенной константы Nil, можно разместить в ней и представление истины - T.
Определение универсальной функции является важным шагом, показывающим одновременно и механизмы реализации языков программирования, и технику функционального программирования на любом языке. Пока еще не описаны многие другие особенности языка Лисп, которые будут рассмотрены позднее. Но все они будут увязаны в единую картину, основа которой согласуется с этим определением.
CAR и CDR не определены для атомарных аргументов. Такие функции, имеющие осмысленный результат не на всех значениях естественной области определения, называют частичными. Отладка и применение частичных функций требует большего контроля, чем работа с тотальными, всюду определенными функциями.Во многих Лисп-системах все элементарные функции вырабатывают результат и на списках, и на атомах, но его смысл зависит от системных решений, что может создавать трудности при переносе программ на другие системы. Базисный предикат EQ всегда имеет значение, но смысл его на неатомарных аргументах будет более понятен после знакомства со структурами данных, используемыми для представления списков в машине.
COND выбрана для начального знакомства как наиболее общая. За редким исключением в Лисп-системе нет необходимости писать в условных выражениях (QUOTE T) или (QUOTE NIL). Вместо них используются встроенные константы T и Nil соответственно.В Лиспе есть два атомных символа, которые представляют истину и ложь соответственно. Эти два атома - T и NIL. Эти символы - реальные значения всех предикатов в системе. Главная причина в удобстве кодирования. Во многих случаях достаточно отличать произвольное значение от пустого списка.
Не существует формального различия между функцией и предикатом в Лиспе. Предикат может быть определен как функция со значениями либо T либо NIL. Можно использовать форму, не являющуюся предикатом там, где требуется предикат: предикатная позиция условного выражения или аргумент логического предиката. Семантически любое S-выражение, только не NIL, будет рассматриватсья как истинное в таком случае. Предикат EQ ведет себя следующим образом:
EQ является NIL.Т.T или NIL в зависимости от того, идентично ли представление аргументов в памяти.EQ всегда T или NIL. Оно никогда не бывает неопределено, даже если аргументы плохие.Выполнено достаточно строгое построение совершенно формальной математической системы, называемой "Элементарный ЛИСП". Составляющие этой формальной системы:
Выполненное определение универсальной функции – макетный образец Лисп-системы, основные черты которой унаследованы многими системами программирования.
| (Apply Функция Список-аргументов ) | Применяет функцию к списку аргументов |
| ( Compile Название ) | Компилирует названную функцию, кроме того сообщает, успешна ли компиляция |
| (Eval Форма ) | Вычисление формы |
| (Funcall Функция Аргумент … ) | Применяет функцию к аргументам |
| (The Тип Форма) | Проверяет имеет ли аргумент указанный Тип |
| (Type-of Данное ) | Выдает тип данного |
| (Quote Форма ) | Форма без вычисления выдается как результат |
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.