Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Основной цикл: READ-EVAL-PRINT




СОДЕРЖАНИЕ

 

1. ВВЕДЕНИЕ В ФУНКЦИИ ……………………………………………… 1. 1. Чистые функции …………………………………………………….. 1. 2. Функциональность ………………………………………………….. 2. ВВЕДЕНИЕ В ФУНКЦИОНАЛЬНОЕ ПРОГРАММИРОВАНИЕ …… 2. 1. О языке Лисп ………………………………………………………... 2. 2. Примеры программ …………………………………………………. 2. 3. Символьная обработка ……………………………………………... 2. 4. Особенности Лиспа ………………………………………………… 3. ОСНОВЫ ЯЗЫКА ЛИСП ……………………………………………….. 3. 1. Символы и списки ………………………………………………….. 3. 2. Понятие функции …………………………………………………… 3. 3. Базовые функции …………………………………………………… 3. 4. Имя и значение символа ……………………………………………. 4. ОПРЕДЕЛЕНИЕ ФУНКЦИЙ …………………………………………… 5. МАТЕМАТИЧЕСКИЕ ОСНОВЫ: l-ИСЧИСЛЕНИЕ ………………… 5. 1. Введение в синтаксис ………………………………………………. 5. 2. Вычисление l-выражений …………………………………………. 5. 3. Порядок редукций и нормальные формы …………………………. 5. 4. Рекурсивные выражения …………………………………………… 5. 5. Чистое l-исчисление ……………………………………………….. 5. 6. Ламбда-абстракции в Лиспе ………………………………………. 6. ВНУТРЕННЕЕ ПРЕДСТАВЛЕНИЕ СПИСКОВ ………………………. 7. РЕКУРСИЯ ……………………………………………………………….. 7. 1. Простая рекурсия …………………………………………………… 7. 2. Другие формы рекурсии ……………………………………………. 8. ФУНКЦИИ БОЛЕЕ ВЫСОКОГО ПОРЯДКА …………………………. 8.1. Функционалы ………………………………………………………... 8.2. Способы композиции функций …………………………………….. 8.3. Замыкания ……………………………………………………………. 8.4. Абстрактный подход ………………………………………………...    

 

ВВЕДЕНИЕ В ФУНКЦИИ

 

Что такое математические функции и как они используются для построения программ с помощью метода композиции. Будет рассмотрено также как для решения тех или иных проблем функция представляется в виде черного ящика; как эти ящики можно компоновать для построения более мощных функций, которые в свою очередь можно также рассматривать в качестве черных ящиков для построения еще более сложных функций. Затем мы исследуем свойство функциональности и обратимся к проблеме языков, не обладающих этим свойством. Используя обычный язык типа Паскаля, мы увидим странные свойства поведения программы, возникающие потому, что язык допускает побочные эффекты, позволяющие изменить состояние вычисления.

Чистые функции

 

Функция (в математике) - отображение объектов из множества величин, названного областью определения функции (доменом), в объекты из некоторого целевого множества, именуемого областью значений функции.

Описание отображения задается правилом.

Пример:

 

sign: {множество целых чисел} --> {плюс, минус, нуль}

 

минус, если x<0,

sign(x) = нуль, если x=0,[ГАсГ1] [ГАсГ2]

плюс, если x<0.

 

Функции полные (тотальные, всюду определенные) и частичные функции.

Пример:

 

sign2(x)= минус, если x<0,

плюс, если x>0. Функция не определена при x=0

 

Функция - черный ящик.

 

Вход (параметр) ---> [ sign ] ---> выход (результат вычисления)

 

Понятия: формальный параметр, фактический параметр, применение функции - процесс подачи на вход функции фактического параметра.

 

Одно из фундаментальных положений функционального программирования: функция является механически зафиксированным правилом преобразования входов в выходы. Черный ящик является конструктивным блоком для функциональной программы, и с помощью объединения таких ящиков можно порождать более сложные операции. Такой процесс “объединения” ящиков называется функциональной композицией.


max(m,n) = m, если m>n,
= n в противном случае.

max: R´R --> R

a b
| |
v v
[ max ]
|
v


max3(a,b,c) = a, если a>=b и a>c или a>=c и a>b,
b, если b>=a и b>c или b>=c и b>a,
c, если c>=a и c>b или c>=b и c>a,
a в противном случае.
(“В противном случае” - это если a=b=c.)
a b c
| | |
| [ max ]
| |
[ max ]
|

max3(a,b,c)=max(a, max(b,c)).

a b c
| | |
[ max3 ]
|

sm4(a,b,c,d) = sign(max (a, max3 (b, c, d))

- вычисляет знак максимального из четырех чисел (можно представить в виде черного ящика).

Таким образом, задав множество предварительно определенных черных ящиков-функций, называемых встроенными функциями или примитивами, для выполнения простых операций, подобных базовым арифметическим, можно построить новые функции, т. е. новые черные ящики для выполнения более сложных операций с помощью этих примитивов. Далее, эти новые функции можно использовать как блоки для построения еще более сложных функций и т.д.

Как и в традиционной практике программирования, мы можем определить новые функции, чтобы или разбить и, следовательно, упростить определение более сложной функции, или описать стандартную операцию и не переписывать одно и то же выражение многократно.

Функциональность

 

Фундаментальное свойство математических функций, которое дает нам возможность собрать воедино черные ящики, - это функциональность (прозрачность по ссылкам). Это означает, что каждое выражение определяет единственную величину, которую нельзя изменить ни путем ее вычисления, ни предоставлением различным частям программы возможности совместно использовать это выражение. Вычисление выражения просто изменяет форму выражения, но не изменяет его величину. Все ссылки на некоторую величину эквивалентны самой этой величине, и тот факт, что на выражение можно ссылаться из другой части программы, никак не влияет на величину этого выражения.

В императивных языках (пример - Паскаль) функции могут ссылаться на глобальные данные и разрешается применять (разрушающее) присваивание, что может привести к изменению значения функции при повторном ее вызове. Такие динамические изменения в величине данных часто именуются побочными эффектами. Благодаря им значение функции может изменяться, даже если ее аргументы и остаются без изменения всякий раз, когда к ней обращаются.

Пример нефункциональности Паскаля:


var flag: boolean;

 

function f (n:integer):integer;

begin

if flag then f:=n

else f:= 2*n;

flag:=not flag

end;

 

begin

flag:=true;

writeln(f(1)+f(2)); ==> 5

writeln(f(2)+f(1)); ==> 4

end.

 

Функция f не является математической (“чистой”) функцией. Операции, подобные этой, в математике не разрешены, поскольку математические рассуждения базируются на идее равенства и возможности замены одного выражения другим, означающим то же самое, т. е. определяющим ту же величину. Вместо представления о переменной как о величине, которая может периодически изменяться путем присваивания ей различных значений, переменные в функциональной программе рассматриваются как переменные в математике: если они существуют, то, следовательно, имеют какую-то величину, и эта величина не может изменяться. Вместо программы, являющейся последовательностью императивов, описывающих, как компьютер должен решать задачу, основываясь на состоянии, изменяемом шаг за шагом (т. е. на изменении переменных в результате присваивания), функциональная программа описывает, что должно быть вычислено, т. е. является просто выражением, определенным в терминах заранее заданных функций и функций, определенных пользователем. Величина этого выражения является результатом программы. Таким образом, тут отсутствует понятие состояния программы и предыстория её вычислений.


ВВЕДЕНИЕ В ФУНКЦИОНАЛЬНОЕ ПРОГРАММИРОВАНИЕ

О языке Лисп

 

Лисп (LISP) был первым чисто функциональным языком. Он был разработан Джоном Маккарти в 1961 году. Хотя оригинальный Лисп был чисто функциональным в смысле прозрачности ссылок, появившиеся в последующие годы диалекты включили в себя многие императивные особенности, в частности конструкции для выполнения разрушающего присваивания, уничтожавшие простоту и элегантность, присущие оригинальному языку. Существует, однако, “чистое” подмножество языка Лисп, встроенное во все диалекты, которое само по себе можно использовать для написания функциональных программ в нашем понимании этого термина. Хотя различные реализации Лиспа отличаются довольно значительно по выбору ключевых слов, имен примитивных функций и структуре программы в целом, в их основе лежат одни и те же принципы.

Мы будем строить наше обсуждение на синтаксисе диалекта Лиспа, называемого XLisp (David Betz, Великобритания, 1988), практически согласованного со стандартом Common Lisp.

Примеры программ

; Определения и использования функций, символ ";" обозначает,

; что дальше до конца строки следует комментарий

; square - возведение в квадрат

(defun square (x) (* x x))

; (max x y) - наибольшее из двух чисел

(defun max (x y)

(if (> x y) x y)

)

; (max3 x y z) - наибольшее из трех чисел

(defun max3 (x y z) (max x (max y z)))

;(div m n) -целочисленное деление

(defun div (m n) (truncate (/ m n)))

; intDiv(m n) -> (m div n, m mod n)

(defun intDiv (m n)

(list (div m n) (mod m n))

)

;"r -действительное число" (analyse r) -> список из трех элементов:

; 1) знак "-" или "+" в зависимости от того, меньше или больше

; число r числа 0;

; 2) значение истинности (T и NIL), показывающее,

; принадлежит ли данное число r диапазону |r| <= 1;

; 3) "ближайшее" целое число к данному

(defun analyse (r)

(list (if (< r 0) '- '+)

(<= (abs r) 1)

(round r)

)

)

; рекурсивная функция для вычисления суммы первых n целых чисел

(defun sum (n)

(if (= n 0) 0 (+ n (sum (- n 1))))

)

Символьная обработка

Традиционные машины (фон Неймана) и языки программирования первоначально разрабатывались для осуществления численных вычислений и обработки больших объемов данных и не подходят столь же хорошо для символьной обработки, которая имеет дело со сложными структурами данных и базами знаний, содержащими правила принятия решений и другие многообразные объекты. Символьная обработка позволяет эффективно работать с такими структурами, как предложения естественного языка, значения слов и предложений, нечеткие понятия и т. д., и на их основе принимать решения, проводить рассуждения и осуществлять другие, свойственные человеку способы обращения с данными.

В этих применениях предполагается представление в подходящей форме символьных и сложно структурированных данных и работа с ними часто ведется в заранее непредсказуемых ситуациях.

Лисп является наиболее важным языком программирования, используемым в исследованиях по искусственному интеллекту и в математической лингвистике. Название языка “Лисп” происходит из “listing processing” (обработка списков).

Лисп опередил свое время. Обычно языки программирования не изобретают, а проектируют. Однако по отношению к Лиспу можно говорить об изобретении. Первоначальная версия языка, в частности, содержала множество понятий и принципов, которые казались очень странными, но многие из которых позже оказались существенным нововведением. Кроме этого, возможность добавления в Лисп в течение десятилетий многих новых черт подтвердила свойство расширяемости этого языка. Вокруг Лиспа возникла широкая культура, охватывающая различные школы и разнообразные диалекты языка, различные системы и методы программирования, программные среды и Лисп-машины.

Особенности Лиспа

Одинаковая форма данных и программы. И то, и другое представляется списочной структурой, имеющей одинаковую форму. Таким образом, программы могут обрабатывать и преобразовывать другие программы и даже самих себя. Можно введенное и сформированное в результате вычислений выражение данных проинтерпретировать в качестве программы и непосредственно выполнить (так называемое программирование, управляемое данными). Универсальный единообразный и простой лисповский синтаксис списка не зависит от применения, и с его помощью легко определять новые формы записи, представления и абстракции. Даже сама структура языка является, таким образом, расширяемой и может быть заново определена. В то же время достаточно просто написание интерпретаторов, компиляторов, преобразователей, редакторов и других средств.

Хранение данных, не зависящее от места. Списки, представляющие программы и данные, состоят из списочных ячеек, расположение и порядок которых в памяти не существенны. Структура списка определяется логически на основе имен символов и указателей.

Автоматическое и динамическое управление памятью. Пользователь не должен заботиться об учете памяти. Система резервирует и освобождает память автоматически в соответствии с потребностью. Когда память кончается, запускается специальный мусорщик. Он собирает неиспользуемые символы и списки, включает их в работу путем вторичного использования. Среда Лиспа постоянно содержится в порядке.

Лисп - безтиповой язык программирования. В Лиспе имена символов, переменных, списков, функций и других объектов не закреплены предварительно за какими-нибудь типами данных. Типы в общем не связаны с именами объектов данных, а сопровождают сами объекты. Таким образом, переменные могут в различные моменты времени представлять различные объекты разных типов.

Заблуждения и предрассудки. А. П. Ершов: “Чувство протеста - вы раз за разом будете ощущать себя как спортсмены, которым нужно играть в волейбол с одной рукой, привязанной к телу. Ощущение трудности и необычности составления функциональных программ вполне законно и естественно”. Мы - жертвы императивного программирования и машин фон Неймана. Естественно, используемые в программировании на Лиспе структуры данных и управляющие структуры часто сложны, поскольку проблемы искусственного интеллекта из-за своей сложности предполагают сложные структуры и программы. Иерархические списочные структуры и Лисп как раз и задумывались для работы со сложными проблемами. Искусственное упрощение структур означало бы пренебрежение действительной сложностью проблем. Новая парадигма - объектно-ориентируемое программирование в Лиспе.

 

 

ОСНОВЫ ЯЗЫКА ЛИСП

Символы и списки

 

Символы используются для представления других объектов. В языке Лисп используются символы и построенные из них символьные структуры. Символ - это имя, состоящее из букв, цифр и специальных знаков, которые обозначают какой-нибудь предмет, объект, вещь или действие из реального мира. В Лиспе символы обозначают числа, другие символы или более сложные структуры, функции и другие лисповские объекты.

Символы в языке Коммон Лисп. Символы могут состоять из букв, цифр и некоторых других знаков, а именно

+ - * / @ $ % ^ & _ > <. (точка)?! { } [ ]:

В состав символов можно включать пробел, запятую, точку с запятой, круглые скобки. Для этого либо символ с двух сторон ограничивается вертикальной чертой (|), либо перед каждым таким специальным знаком, входящим в символ, ставится обратная косая черта (\).

Русские буквы в XLisp не используются.

Символы могут состоять из строчных и прописных латинских букв, которые отождествляются и представляются прописными буквами.

Числа являются константами. В языке используются числа в обычной записи. Числа не являются символами, так как число не может представлять иные лисповские объекты, кроме самого себя, т. е. своего числового значения. Примеры чисел различных типов: 56, 67.89, 56.45 E -3, 5/8.

Логические значения T и NIL. Символы T и NIL имеют специальное назначение: T обозначает логическое значение "истина", NIL обозначает "ложь". Символы T и NIL всегда имеют одно и то же фиксированное встроенное значение. Их нельзя использовать в качестве имен других лисповских объектов. Важное замечание: значение "истина" изображается любым объектом Лиспа, отличным от символа NIL.

Константы и переменные. Числа и логические значения T и NIL являются константами, остальные символы – переменными, которые используются для обозначения других лисповских объектов.

Атомы = символы + числа. Символы и числа представляют собой те простейшие объекты Лиспа, из которых строятся остальные структуры. Они называются атомарными объектами или атомами.

Построение списков из атомов и подсписков. Список в Лиспе - упорядоченная последовательность, элементами которой являются атомы или списки (подсписки). Списки заключаются в круглые скобки, элементы списка разделяются пробелами. Список всегда начинается с открывающей скобки и заканчивается закрывающей скобкой.


Пример: (56 g (a (b) s) 1/2 +)

Список - это многоуровневая структура данных, в которой открывающие и закрывающие скобки должны быть в строгом соответствии (сбалансированы).

Пустой список. Список, в котором нет ни одного элемента, называется пустым и обозначается () или NIL.

Атомы и списки называются символьными выражениями.

Различная интерпретация списков. Структурные данные и программы в Лиспе представляются в виде списков. Например, список (+ 3 4)
можно интерпретировать в зависимости от окружения и использования либо как действие, дающее в результате число 7, либо как список, состоящий из трех элементов.

Понятие функции

 

Единообразная префиксная нотация. В языке Лисп как для вызова функций, так и для записи выражений принята единообразная префиксная форма записи, при которой как имя функции или действия, так и сами аргументы записываются внутри скобок:

(f x), (g x y), (h x (g y z)) и т. д.
Таким же образом записываются арифметические действия:

(+ x y), (* x (+ y z)) и т. д.

Лисп содержит также и средства, необходимые для задания способа записи и расширения языка в желаемом направлении.

Вычисляя значение функций, не нужно осуществлять сложный синтаксический анализ выражений, так как сразу по первому символу текущего выражения система уже знает, с какой структурой имеет дело и как её интерпретировать или как с ней обращаться.

Диалог с интерпретатором Лиспа. Лисп обычно используется в диалоге (интерактивно) в режиме интерпретации.

Обычный цикл работы Лиспа:

· приглашение интерпретатора для ввода >,

· пользователь вводит выражение,

· интерпретатор вычисляет выражение и выдает значение этого выражения.

Иерархия вызовов. В конструкцию вводимой функции могут, в свою очередь, входить функциональные подвыражения. Тогда аргументы вычисляемой функции заменяются на новые вычисления, ведущие к определению значений этих аргументов. Таким путем вычисления сводятся, в конечном счете, к вычислению выражений, значения которых как, например, констант можно определить непосредственно.

Вычисляя значения выражения, интерпретатор Лиспа сначала пытается слева направо вычислить значения аргументов внешнего вызова. При необходимости этот процесс рекурсивен.

QUOTE блокирует вычисление выражения. В некоторых случаях не надо вычислять значение выражения, а нужно само выражение. Нас, например, может не интересовать значение функционального вызова (+ 2 3), равное 5, а мы хотим обрабатывать форму (+ 2 3) как список. В таких случаях используют специальную функцию QUOTE с одним аргументом, которая ничего с ним не делает, даже не вычисляет его значение, а возвращает в качестве значения вызова сам этот аргумент:

> (quote (+ 2 3))

(+ 2 3)
В качестве краткого обозначения для функции QUOTE используют апостроф перед аргументом:

‘выражение<===> (quote выражение)
Поэтому

> ‘(+ 2 ‘(* 3 5))

(+ 2 (quote (* 3 5)))

Числа и константы T и NIL не надо предварять апострофом.

 

На месте имени функции в функциональном вызове апостроф не используется. Интерпретатор Коммон Лиспа не допускает использование в качестве первого элемента вызова функции вычисляемого выражения.

Базовые функции

 

First, rest, cons. Базовые функции для построения, разбора и анализа списков.

Если список не пуст, то он имеет вид (голова списка - первый элемент, хвост списка).

(first <head tail>) --> <head>

(first список) —> символьное выражение (s- выражение)

(first nil) ---> nil

(first атом) ---> ошибка

(rest <head tail>) --> <tail>

(rest список) ---> список

(rest nil) --> nil

(rest атом) --> ошибка

 

Традиционно (в связи с первоначальной реализацией Лиспа) для функций first и rest используются также обозначения car и cdr.
(first ‘(1 2 3)) ==> 1
(rest ‘(1 2 3)) ==> (2 3)

 

Функция CONS (construct) строит новый список из переданных в качестве аргументов головы и хвоста:


(cons ‘a ‘(b c)) ==> (a b c)
(cons ‘(a b) ‘(c d)) ==> ((a b) c d)
(cons (+ 1 2) ‘(+ 4 6)) => (3 + 4 6)
(cons nil nil) ==> (nil)
(cons ‘(a b c) nil) ==> ((a b c))
(cons nil ‘(a b c)) ==> (nil a b c)

 

Связь между функциями first, rest, cons:
(cons (first ‘(a b c))
(rest ‘(a b c))) ==> (a b c)

 

Комбинируя селекторы car=first и cdr=rest, можно выделить произвольный элемент списка. Например,

(cdr (cdr (car ‘((a b c) (d e) (f))))) ==> (c)
Вложенные вызовы CAR и CDR можно записывать в сокращенном виде в виде одного вызова функции:

(C...R список).
(cadr x) <==> (car (cdr x))
(cddar x) <==> (cdr (cdr (car x))) (не больше 4-х символов вместо точек)

 

Предикаты – функции, которые проверяют выполнение некоторого условия и возвращают в качестве результата логическое значение T (в более общем виде, произвольное выражение, отличное от NIL) или NIL.

(ATOM s-выражение) - проверяет, является ли выражение атомом.
(atom ‘(a b c)) ==> nil
(atom 7) ==> t
(atom nil) ==> t
(atom (atom (+ 3 4))) ==> t

(NULL s-выражение) - проверяет, является ли аргумент пустым списком.
(null ‘(3 4 5)) ==> nil
(null ()) ==> t
(null ‘a) ==> nil

(EQ < символ1 > < символ2 >) - проверяет тождественность двух символов:
(eq t (atom ‘atom)) ==> t
(eq nil t) ==> nil

(= < число 1> < число2 >) - проверяет равенство двух чисел.

EQL -сравнивает символы и числа одинаковых типов. Предикат используется во многих встроенных функциях, осуществляющих более сложные операции сравнения. Его использование для сравнения списков - типичная ошибка.

EQUAL работает какeql, но, кроме того, проверяет одинаковость двух списков.

Функции second, third, fourt, fifth, sixth, seven, eighth, ninth, tenth выдают второй, третий,…, десятый элемент списка.

(nth n список ) - выдает n-ый элемент списка.

(Last список ) -список, состоящий из последнего элемента списка-аргумента

(last ‘(a b c)) ==> (c)

 

(list x1 x2 x3...) - возвращает в качестве своего значения список из значений аргументов:

(list 1 2) ==> (1 2)

(list ‘a ‘(b c) ‘ d) ==> (a (b c) d)

(list (list ‘a) ‘b nil) ==> ((a) b nil)

(list nil) ==> (nil)

Имя и значение символа

 

Символы можно использовать как переменные. В этом случае они могут обозначать некоторые выражения. У символов изначально нет какого-нибудь значения, как у констант.

При помощи функции SET символу можно присвоить (set) или связать (binding) с ним некоторое значение. SET вычисляет оба аргумента.

> a ==> ошибка (unbound variable)

(set ‘a ‘(1 2 3))

> a ==> (1 2 3)

 

Функция SETQ отличается от SET тем, что она вычисляет только свой второй аргумент. Об автоматическом блокировании вычисления первого аргумента напоминает буква Q.

(setq b a)

>b ==> (1 2 3)

 

Эти функции имеют побочный эффект. Эффект функции состоит в образовании связи между символом и его значением, а значением функции является связываемое значение.

В Лиспе все действия возвращает некоторое значение. Значение имеется даже у таких действий, основное предназначение которых заключается в осуществлении побочного эффекта, таких, например, как связывание символа или вывод результатов на печать. Функции, обладающие побочным эффектом, в Лиспе называются псевдофункциями. В практическом программировании псевдофункции полезны, хотя в теории, чистом функциональном программировании не нужны.

(list (+ (setq a 3) 4) a) ===> (7 3)

Интерпретатор Лиспаназывается EVAL, и его можно так же, как и другие функции вызывать из программы. Лишний вызов интерпретатора может, например, снять эффект блокировки вычисления или позволяет найти значение значения выражения.

‘(+ 2 3) ==> (+ 2 3)

(eval ‘(+ 2 3)) ==> 5

 

(setq x ‘(a b c))

‘x ==> x

(eval ‘x) ==> (a b c)

 

(setq y ‘x)

> y ===> x

(eval y) ===> (a b c)

 

Основной цикл: READ-EVAL-PRINT

(print ‘>)

(setq a (read))

(setq b (eval a))

(print b)

(print ‘>)


ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

 

Дать имя и определить новую функцию можно с помощью функции DEFUN (define function). DEFUN вызывается так:

(DEFUN имя список_формальных_аргументов тело)

Пример:

(defun list2 (x y) (cons x (cons y nil)))

 

Передача параметров в Лиспе осуществляется в основном по значению. Параметры в Лиспе используются преимущественно лишь для передачи данных в функцию, а результаты возвращаются как значение функции, а не как значения параметров переданных по ссылке.

 

Форма -символьное выражение, значение которого может быть вычислено интерпретатором:

· константы;

· символы, которые используются в качестве переменных;

· определения функций и вызовы функций;

· специальные формы (SET, SETQ, SET, QUOTE, COND, IF и другие).

Разветвление вычислений: условное предложение COND. Это синтаксическая форма, позволяющая управлять вычислениями на основе определяемых предикатами условий. Структура условного предложения такова:

 

(cond (p1 a1)

(p2 a2)

..........

(pN aN))

 

Предикатами pi и результирующими выражениями ai могут быть произвольные формы. Значение предложения COND определяется следующим образом.

1. Выражения pi, выполняющие роль предикатов, вычисляются последовательно слева направо (сверху вниз) до тех пор, пока не встретится выражение, значением которого не является NIL, т. е. логическим значением которого является истина.

2. Вычисляется результирующее выражение, соответствующее этому предикату, и полученное значение возвращается в качестве значения всего предложения COND.

 

3. Если истинного предиката нет, то значением COND является NIL.

Рекомендуется в качестве последнего предиката использовать символ T.

 

(defun sign (x)

(cond ((> x 0) ‘positive)

((< x 0) ‘negative))

(t ‘zero))

)

 

В условном предложении может отсутствовать результирующее выражение ai или на его месте может быть последовательность форм:

 

(cond (p1 a11)

............

(pi)

.......

(pk ak1 ak2 akN)

.........)

 

Если условию не ставится в соответствие результирующее выражение, то в качестве результата предложения COND при истинности предиката выдается само значение предиката. Если же условию соответствует несколько форм, то при его истинности формы вычисляются слева направо и результатом предложения COND будет значение последней формы последовательности.

 

(IF условие то-форма иначе-форма)

эквивалентно

(COND (условие то-форма)

(T иначе-форма))

LET создает локальную связь. Вычисление вызова функции создает на время вычисления новые связи для формальных параметров функции. Новые связи внутри формы можно создавать и с помощью предложения LET. Эта структура (немного упрощенно) выглядит так:

 

(let ((m1 знач1) (m2 знач2)...)

(форма1 форма2...)

)

Форма LET вычисляется так, что сначала локальные переменные m1, m2,... из первого “аргумента” формы связываются (одновременно) с соответствующими значениями знач1, знач2,.... Затем слева направо вычисляются значения форм форма1, форма2,.... В качестве значения всего LET возвращается значение последней формы. Как и у функций, после окончания вычисления связи локальных переменных m1, m2,... ликвидируются и любые изменения их значений не будут видны извне.

 

(setq x 2)

> x ==> 2

(let ((x 0))

(setq x 1))

==> 1

> x ==> 2

 

(let ((x 2) (y (* 3 x)))

(list x y))

===> unbound atom x

 

Примеры программ

; квалифицированные выражения и локальные функции

; неудачное определение

(defun f1 (x)

(+ (square (max x 4))

(if (<= x 1) 1 (square (max x 4)))

)

)

; вспомогательная функция

(defun g (a b)

(+ a (if (<= b 1) 1 a))

)

(defun f2 (x) (g (square (max 4 x)) x))

; использование квалифицированного выражения

(defun f3 (x)

(let

((a (square (max 4 x))))

(+ a (if (<= x 1) 1 a))

)

)

; использование локальной функции

(defun f4 (x)

(flet

((a (y) (square (max 4 y))))

(+ (a x) (if (<= x 1) 1 (a x)))

)

)

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...