ЛЕКЦИИ -...

68
ЛЕКЦИИ ЕЗИК ЗА ФУНКЦИОНАЛНО ПРОГРАМИРАНЕ (LISP)

Upload: phunglien

Post on 28-Feb-2018

261 views

Category:

Documents


18 download

TRANSCRIPT

Page 1: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИИЕЗИК ЗА ФУНКЦИОНАЛНО ПРОГРАМИРАНЕ

(LISP)

Page 2: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИЯ 1ЛЕКЦИЯ 1

УВОД В ДИСЦИПЛИНАТА

Изкустен интелект и езици за дескриптивно програмиране. Основи н функционалното програмиране. Среда за функционално програмиране DrScheme.

1.УВОД В ДИСЦИПЛИНАТА

1.1. АнотацияДисциплината е задължителна. Курсът съдържа два раздела: Функционално

програмиране и Логическо програмиране. В първия раздел се разглеждат фундаменталните принципи на функционалния

стил за програмиране. Подробно се изучават основните елементи и структури на езика за програмиране LISP. При разработката на примерите и упражненията е използван стандарта на езика, като са посочени различията за диалектите PLT Scheme и PC Scheme.

Вторият раздел е посветен на логическия стил за програмиране. Подробно се разглеждат основите на езика Prolog и типичните му приложения. Примерите и упражненията са реализирани на диалекта Strawberry Prolog.

1.2.Условия за допускане до изпит По време на семестъра се провеждат две контролни работи. На лабораторните

упражнения студентите изпълняват индивидуални протоколи. На базата на тези оценки се определя текуща оценка за всеки студент. Ако тази оценка е 5.50 или по-висока, студентът се освобождава от изпит. При оценка между 4.50 и 5.49, студентът се освобождава от практическата част по съответния раздел на изпита.

При текуща оценка по-ниска от 3.00 студентът не се допуска до изпит на редовна сесия.

1.3.Изпитна процедура, критерии за оценяване и присъждане на кредити

Изпитът е двукомпонентен: практически и теоретичен. Успешно положилите практическата част се допускат до теоретичната част на изпита. Оценката се определя като средно аритметична от практическата и теоретичната част.

Студентите трябва да знаят основните принципи на функционалния и логическия стил на програмиране. Да могат да проектират и програмират самостоятелно практически задачи, прилагайки функционалната и логическата парадигма в програмирането. При успешно полагане на изпита се присъждат 8 кредита.

1.4. Литература1. .Абелсън Х., Сасмън Дж., Структура и интерпретация на компютърни програми,

С., СОФТЕХ, 1994.2. Геров, А. и Теодосиев Т. Езици за функционално и логическо програмиране,

учебно пособие, изд. Шуменски университет, 2006.3. Д.Дочев, Х.Дичев, З.Марков, Г.Агре, Програмиране на Пролог: основи и

приложения, С., Наука и изкуство, 1989.4. Клоксин У., Меллиш, К. Программирование на языке Пролог, М., Мир, 1987.5. Тодорова М., Езици за функционално и логическо програмиране, I част

Функционално програмиране, Сиела, С., 2003.

2

Page 3: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

6. Тодорова М., Езици за функционално и логическо програмиране, IІ част Логическо програмиране, Сиела, С., 2003.

7. Bratko, I. Prolog Programming for Artificial Intelligence (2nd ed.), Addison-Wesley, 1990.

8. P.Winston, B.Horn, Lisp (3rd ed.) Addison-Wesley, 1989.

2. ИЗКУСТВЕН ИНТЕЛЕКТ И ЕЗИЦИ ЗА ДЕСКРИПТИВНОТО ПРОГРАМИРАНЕ

2.1. Изкуствен интелект.Езиците за дескриптивно програмиране намират най-често приложение за

разработване на системи с изкуствен интелект. Може да се даде следното кратко определение:

Изкуственият интелект изучава начините, по които могат да се създават програмни системи, базирани на знания, при които знанията за конкретната предметна област са отделени от програмната част.

Това определение се основава на разделението на труда – специалистите по програмиране да разработват алгоритмите и програмите за работа със знания (така както един изчислителен алгоритъм работи с числови данни), а специалистите в конкретната област (например медиците – диагностици) да описват своите знания. За достатъчно популярен пример могат да се споменат експертните системи, които работят върху база от правила, въведени от съответните специалисти в конкретната област, а програмната част анализира, кое правило се удовлетворява от текущите данни.

По-подробно тази тематика ще се изучава в дисциплините: Изкуствен интелект и Експертни системи.

2.2. Стилове на програмиране.Съществуват два основни стила на програмиране:- императивен(процедурен) и - дескриптивен (декларативен).При императивния стил на програмиране е валидна схемата:

ПРОГРАМА = АЛГОРИТЪМ + СТРУКТУРИ ОТ ДАННИ

Алгоритъмът показва последователността от действия при обработка на данните за да се получи крайния резултат.

Решението се свежда до описанието КАК да се получи резултата.Този вид езици е свързан с архитектурата на съвременните компютри, която се

нарича Нойманова по името нейния създател - Джон фон Нойман. Те са абстрактна версия на този тип архитектура.

Такива са машинните, асемблерните езици и FORTRAN, BASIC,PL,ALGOL,PASCAL,ADA и други.

Проблемите които възникват при този вид езици са:- относително малка мощност;- ниска производителност;- липса на гъвкавост;- не притежават полезни математически свойства.Основното им предимство е широкото разпространение на компютри с

Нойманова архитектура.

3

Page 4: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

При дескриптивните езици, парадигмата на програмиране е различна – в програмата се описват свойствата на желания резултат, но не показва пътя за как да бъде постигнат.

ПРОГРАМА = СПИСЪК ОТ ФУКЦИИ ИЛИ РАВЕНСТВА ИЛИ ПРАВИЛА + ФАКТИ

Схемата на изпълнението има вида:

ИЗПЪЛНЕНИЕ = РЕДУКЦИЯ ИЛИ ИЗВОД(ДОКАЗАТЕЛСТВО)

Дескриптивните езици описват КАКВО се пресмята, а не КАК. Такива са: LISP, PROLOG, POP-11,TABLOG и други.

Основният им недостатък, е че не може да се направи ефективна реализация на съществуващите Нойманови компютри.

Това налага разработване на нови ненойманови архитектури наречени под общото име пето поколение компютри.

2.3. Характеристики на дескриптивните езици за програмиране.Основната характеристика на този тип програмни системи, отличаваща ги от

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

Представянето на знанията в тази функционална част е много по-различно от представянето на данните в традиционните програмни системи. Използват се списъци с различна дължина и нива на вложение, правила за връзките между различни класове обекти, функции, които генерират различни действия в зависимост от конкретните входни факти, граматични схеми за разпознаване на езиков интерфейс, близък до естествения и пр.

По-съществените характеристики на дескриптивните езици са следните:- работа със списъци;- дефиниране на рекурсивни функции за нечислови (символни) пресмятания;- динамично формиране на обръщения към функции;- използване на агрегатни функции;- съпоставяне по образец;- генериране на алтернативни решения;- за реализиране на подхода “проба и грешка” или обхождане с връщане назад;- за въвеждане на знания във вид на формули (логически);- използване на логически извод;- визуален и звуков вход и изход.

Езиците за функционално програмиране (ЛИСП) и за логическо програмиране (ПРОЛОГ) до голяма степен съдържат такива възможности или с помощта на тези езици лесно могат да се реализират такива. Поради това, тези два езика са и най-

4

Page 5: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

използваните при проектиране на програмни системи, базирани на знания. Много често такива програмни системи представляват само някаква част от по-голяма система. В такъв случай крайният вариант на програмите може да е програмиран и на друг алгоритмичен език Използването на традиционен език за програмиране може да се наложи и от изисквания за бързодействие. Но за разработването на прототипите на програмни системи, базирани на знания и експерименталното им прилагане е значително по-добре да се използват средствата, предоставени от езиците за функционално и логическо програмиране.

3. ОСНОВИ НА ФУНКЦИОНАЛНОТО ПРОГРАМИРАНЕ.

3.1.Теоретичният модел на функционалното програмиране.

Базира се на:• λ- изчислението въведено от Чърч;• математически функции и ג-смятането (Alonzo Church);• метод за дефиниране на функции без име – lambda функции (Alonzo Church,

1941);• Бекус, 1978 поставя началото на функционалния стил за програмиране,

използващ примитивни форми, дефиниции или функционални форми.

3.2. Особености• Програмата представлява съвкупност от дефиниции на функции;• Възможно е многократно влагане на функциите една в друга;• Единствения начин за разделяне на програмата на части е въвеждането на име

на функция и задаването на това име на израз, който пресмята стойността на функцията програмите представляват дефиниране на функции;

• Единственото правило за композиция е суперпозицията на функции;• Не използват променливи и оператори за присвояване - итеративните

конструкции не са възможни;• Повторенията се реализират чрез рекурсия;• Еднакво представяне на код (функции) и данни;• Изпълнението на функция винаги дава същия резултат при същите входни

параметри;• Проста семантика;• Задават множества от примитивни функции и функционални форми за

конструиране на съставни функции, операции, и някои структури за представяне на данните;

• Използват се по-често интерпретатори.

3.3. Видове • Чист функционален език (управляващите конструкции са функциите,

функциите не допускат странични ефекти) – ЧИСТ LISP, Haskell, HOPE, Miranda, FP, W;

• Нечист функционален език (управляващите конструкции са функции и императивни конструкции, функциите допускат странични ефекти) – Scheme(Ским), Common Lisp, ML(1980), Golden Lisp, ... (диалекти на LISP), APL;

• Логически и функционални езици – N, F, R, HASL, FUNLOG, QUTE, LOGLISP, QLOG, PIL, W, Prolog-with-Equality, EQLOG, TABLOG, UNICORN, Pop-11, LEAF, APPLOG.

5

Page 6: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

През 1958-1961г. Маккарти разработва езика за функционалното програмиране LISP. LISt Processing (LISP, Makkarti, 1950) – първо е описан като математически формализъм. Може да се охарактеризира като:

o най-старият и най-разпространеният;o много диалекти;o първият диалект е за IBM 704;o За символна обработка и задачи от ИИ;o Безтипов език;o Притежава императивни черти – променливи, присвояване и итерацияo Префиксен запис - произволен брой аргументи (funname arg1 arg2 …argn)

Механизмът му на работа е: Четене – оценка – отпечатване. Примери:

Пресмятане на сумата на 1 и 2 на LISP е:> (+ 1 2)3Предимство на префиксния запис: произволен брой аргументи:> (+ 1 2 3) 6>(define pi 3.14)pi>pi3.14Ако трябва да се дефинира функцията: f(x) = x3 на LISP това се извършва по

следния начин:>(define (cube x)

(* x x x))Използването на функцията за изчисляване на 23 е така:>(cube 2)8По нататък ще бъдат разгледани примери, които разкриват различните

възможности на езика.

4. СРЕДАТА ЗА ФУНЦИОНАЛНО ПРОГРАМИРАНЕ DRCHEME.

Scheme (Ским) е модерен диалект на LISP с богати възможности практически приложения и обучение. Има много ефективни реализации на PC с добра производителност и възможности за символни обработки. Такива са DrScheme, MIT-Sheme и др.

Функциите му могат да бъдат стойности на изрази и елементи на списъци, могат да бъдат присвоявани на променливи и предавани като параметри

DR Scheme е една сериозна реализация на Scheme, която е удобна за обучение и разработване на по-сериозни приложения.

Има малки системни изисквания: MS WONDOWS 9X и по-нова версия и около 11 Мб дисково пространство.

Строго погледнато тази реализация на Sheme е MzScheme, а DrScheme това е MzScheme + библиотеки + пълна версия на помощната информация + удобна среда за разработка.

Възможно е да се работи в разлчини режими: от начинаещи (Beginning Student) до напреднали студенти (Advanced Student) и професионалисти (Full).

6

Page 7: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Интересни са възможностите предоставяни от библиотеката на дистрибутива: много поточност, работа в мрежа, работа с протоколите на Интернет и HTML/XML, обектно ориентирано програмиране, създаване на самостоятелно стартиращи се файлове, и главното – създаване на крос платформен графически интерфейс за потребителя (в стил Tcl/Tk, но много по мощен).

Най-интересните библиотеки, невключени в свободно предлагания дистрибутив са: StPersist (интерфейс към ODBC за Win32/Unix), MysterX (работа с ActiveX в Win32), GUI-builder (инсталира се като библиотека; визуален редактор за интерфейси). Като недостатък може да се отнесе лошата поддръжка на макроси, а също липсата на поддръжка на славянски езици (и всички кодировки, различни от Latin-1) във версията за X windows.

На фиг.1. е показан основния прозорец на средата.

Фиг. 1. Основен прозорец

Горният прозорец - Definitions е пълнофункционален, графичен редактор с ключови възможности и обвивка подобна на EMACS. Редакторът поддържа оцветяване в реално време на синтаксиса.

Долния Interactions, прозореца осъществява read-eval-print (REPL) цикъла.

Бутонът Run зарежда съдържанието от Definitions прозореца в Interactions прозореца.

REPL в DrScheme е явен, което позволява проследяване на грешките и избягване на недоразуменията. Това става по два начина:

• всеки път когато потребителя кликне върху бутонът Run DrScheme изтрива всички вътрешни статични асоциации с REPL

7

Page 8: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

• DrScheme предупреждава потребителите когато те правят промени да не кликват върху Run а да изчисляват изразите чрез REPL

Фиг. 2. Функциониране на REPL

Начинаещите правят грешки и се нуждаят от обратна връзка и промяна на своето нивото на разбиране. DrScheme предлага йерархия на езиковите нива (фиг. 3):

• Beginning Student language – език за начинаещи включва функции, структури и списъци

• Intermediate Student language – език за средно ниво на познание, добавя в обсега си и лексикални конструкции

• Advanced Student language – език на напредналите позволява мутации и поддържа разширения

• Езиковите нива на Scheme предлагат стандартен Scheme с или без графични възможности и дебъгер

8

Page 9: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Фиг.3. Езикови нива на DrSchemeЕзиковите нива налагат различни синтактични и семантични ограничения

базиращи се на общи грешки наблюдавани при студентите. При стартирането за първи път на DrScheme се установява на ниво Beginning Student и налага строги ограничения. Ако желаете незабавно да превключите на Standard Scheme използвайте някоя от възможностите на Choose Language менюто.

9

Page 10: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИЯ 2ЛЕКЦИЯ 2

ОСНОВНИ ЕЛЕМЕНТИ НА ЕЗИКА ЛИСП

Атоми. S-изрази. Списъци. Функции и изрази в ЛИСП. Функциите CAR и CDR. Функцията CONS. Функцията SETQ. Апликативност и функционалност.

Основната структура в езика ЛИСП е списък. С помощта на списъци се представят, както данни, така и действия, които трябва да извърши програмата на ЛИСП. С други думи, данните и програмите в езика се представят по един и същ начин, което го отличава от почти всички други езици и дава възможност за промяна на програмите по време на изпълнение. От своя страна списъците се конструират, както от други списъци, така и от основната неделима единица в езика – атома.

1.АтомиАтомите представляват такива елементарни единици, за които в другите

“традиционни” езици за програмиране се използват константи, променливи и имена на различни обекти – функции, масиви, структури от данни и пр.

Атомите могат да се разделят на три основни групи:а) символни атоми – поредица от букви и цифри, започващи с буква, например:

А – атом от една буква,R12 – атом, в който има цифриАТОМ – атом от 4 букви,СПОРТ_ТОТО – атом от 10 букви (знакът _ се възприема като буква).

Забележка: В някои диалекти в името на символните атоми може да се използват и някои специални символи, например: ATOM?

Дължината на атомите е ограничена единствено от възможностите на конкретната реализация;

б) числени атоми – цели и реални числа, които се записват по общоприетия в езиците за програмиране начин – например както на езика С. В различните версии на езика има разнообразни видове числа – двоични, шестнайсетични, с произволна основа, рационални (числител и знаменател, разделени с наклонена черта), комплексни, с неограничена точност и пр.

в) низове – произволна поредица от знаци, заградени от специален знак, зависещ от конкретната реализация, например:

"А" – низ от един знак,"А = В + С" – низ от 9 знака," ((:=8иг *НН" – низ от 11 знака.

Атомите могат да имат стойност и да се използват като променливи аналогично на използването на променливите в другите алгоритмични езици. Освен това името на един атом също може да бъде обект на символна обработка. Например в езика съществуват средства, с помощта на, които от атома SUMAX може да се получи атома SYMAY. Това, както по-нататък ще видим, може да се използва за динамично променяне на програмата в процеса на работа.

Има и два специални атома – тяхната стойност е самия атом. Това са атомите #T и NIL(няма го в DrScheme) . С атома NIL, както ще видим по-долу, се означава край на списък. При логическите операции #T означава истина, а NIL(() в PC Scheme) – лъжа. В DrScheme при логическите операции с #t се означава истина, а с #f - лъжа.

10

Page 11: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

2. S-изразиS-изразите са основна конструкция на езика. Те се дефинират посредством

следните три правила:а) всеки атом е S-израз;б) ако X и Y са S-изрази, то (X . Y) е също S-израз;в) S-изразите се определят само по правилата а) и б).Двойката (X . Y) се нарича още точкова двойка. Така всеки S-израз е или атом,

или точкова двойка.

Пример: Нека A, B, C, и D са атоми. Тогава ((A . B) . (C . D)) е S-израз.Удобен начин за представянето на точковите двойки е даден на фиг. 1, като с X*

и Y* са означени съответните графични представяния на S-изразите X и Y.В такъв случай S–изразът, даден в горния пример, ще се представи по начина на фиг.2.

Фиг.1. Фиг.2.

3. Списъци

Нека X1, X2, X3,… , XN са S–изрази. Тогава изразът(X1 . (X2 . (X3 . ( … . (XN . NIL) … ))))

се нарича списък. Прието е такъв списък да се записва съкратено във вида:(X1 X2 X3 … XN)

където X1, X2, X3,…, XN са елементи на списъка. Тъй като те са S-изрази, то те могат да бъдат атоми, точкови двойки или списъци. По този начин могат да се влагат списъци един в друг.

По дефиниция празният списък ( ) е еквивалентен на атома NIL!!!Освен изброените, в различните версии на езика, се допускат и различни други

структури данни като например вектори, масиви, дървовидни структури, записи, различни видове числа (адресни константи, цели числа, числа с фиксирана точка, числа с плаваща точка и др.).

В някои диалекти на езика вместо термина атом се използва термина символ, което е свързано с факта, че атомите обикновено се използват за именуване на по-сложни обекти– списъци, структури, функции и др.

Примери1.Съкратеният запис на S-израза (A . (B . (C . NIL))) ще бъде (A B C), а графичното му представяне е дадено на фиг. 3.2.Нека е даден S-изразът (A . (B . NIL)). Съкратеният му запис е (A B), а графичното му представяне е показано на фиг. 4.

11

X* Y*A

BBC

DY*B D

Page 12: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Фиг. 3. Фиг. 4.Друг начин за графично представяне е чрез двойки указатели. Например

списъците (A B), (A B C) и ((P O) B C)) могат да бъдат представени по начина, даден на фиг.5 .

. . .

A B . . . . .

A B C . . . . .

B C . . .

P O Фиг.5.

Графичното представяне на S-изразите е до голяма степен аналогично на представянето на S-изразите в оперативната памет на компютъра. Поради това, като се анализира графичното представяне, могат да се правят редица изводи относно изпълнението на някои дейности в една програма на ЛИСП. Вижда се например, че търсенето на елемент в края на списък е по-сложно и по-бавно, отколкото вземането на първия му елемент.

Да разгледаме как може да се вмъкне елемент в началото на списък. Нека е даден списъка (A B) и искаме да вмъкнем елемента E в началото на този списък така, че да получим списъка (E A B). Графично това е илюстрирано на фиг. 6, като с пунктир са означени връзки, които са необходими за получаването на списъка (E A B).

. .

12

Y*

Nil

A

B

Y*

Y*

A

B

C Nil

Page 13: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

E

. . .

A B Фиг. 6

Елементите на един списък могат да бъдат изследвани по следния начин: взема се първия елемент, изследва се, премахва се от списъка, взема се следващия елемент (той вече е станал първи елемент), изследва се и т.н. по същия начин, докато се стигне края на списъка. Първият елемент на списъка се премахва като се премахва указателя (виж фиг. 7).

. . . . .

E A B Фиг. 7

4. Функции и изрази в ЛИСППрограмата на ЛИСП представлява последователност от изрази, които се

изчисляват. Изразите от своя страна по правило са обръщения към функции. Поради това езикът ЛИСП се смята за функционален език. Простият случай на обръщение към функция представлява списък, на който първият елемент е името на функцията, а следващите елементи са аргументите, с които тази функция трябва да се изпълни. Името на функцията трябва да е символен атом. Позволено е влагане на функции, което ще рече, че на мястото на аргумента (а и на мястото на име на функция) може да стои също едно обръщение към функция, представено чрез съответния списък.

Ако използваме ъгловите скоби < и > за ограждане на понятията от езика, то определението на <ОБРЪЩЕНИЕ КЪМ ФУНКЦИЯ> изглежда така:

<ОБРЪЩЕНИЕ КЪМ ФУНКЦИЯ > е (<ИМЕ НА ФУНКЦИЯ ><АРГУМЕНТ-1> … <АРГУМЕНТ-n>).<ИМЕ НА ФУНКЦИЯ> е <АТОМ> или <ОБРЪЩЕНИЕ КЪМ ФУНКЦИЯ>.<АРГУМЕНТ-i > е <АТОМ> или <ОБРЪЩЕНИЕ КЪМ ФУНКЦИЯ>.

От определението се вижда, че е възможно влагане на функции. В този случай по време на изпълнение се навлиза до най-ниското ниво на влагане и оттам започва изпълнението на функциите в обратен ред, докато се стигне до най-високото ниво. За да се осъществи този процес на изпълнение на вложени функции, е необходимо да се организира стекова памет.

В ЛИСП “израз” представлява атом, обръщение към функция и др. В резултат на изпълнението на функция може да се получи израз, представляващ обръщение към функция. Това става с помощта на функциите LIST, EVAL и макродефинициите, които ще бъдат разгледани по-късно.

Един съществен клас от функции в ЛИСП са така наречените вградени функции. Те са част от транслатора и са оптимизирани по време и памет. Освен това програмистът може сам да си дефинира функции с помощта на функцията DEFUN.

13

Page 14: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Така дефинираните функции могат след това да бъдат използвани подобно на вградените.

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

При нашите по-нататъшни разглеждания ще използваме следните означения:а) Означение за стойност на атом: “[ ]”. Стойността на атома A означаваме с [A]

и “[A] е 5”, ще разбираме като “стойността на атома A е 5”. Същото твърдение ще означаваме и по следния начин: A -> 5. По подобен начин ще означаваме и стойност на функция.

б) Означение за еквивалентност: “≡”. Този знак ще използваме при преобразуване на конструкция от езика, при което се получава нова конструкция, еквивалентна на първата, в смисъл че представянето на изразите по двата начина води до едно и също вътрешно представяне, или че двата израза водят до едни и същи действия.Пример: (A B) ≡ (A . (B . NIL)))Тези означения не са знаци от езика, а от метаезика, т.е. от езика, който използваме за описание на езика ЛИСП.

Сега ще разгледаме най-простите функции в езика, които извършват основните действия с S-изрази – разделяне на един списък, конструиране на списък и присвояване на стойност на атом.

5. Функциите CAR и CDRТези две функции служат за достъп до елементите на точкова двойка. Първата

функция позволява да се получи първия елемент на точковата двойка, а в случая на списък – първия елемент от списъка. Чрез втората функция се извършва достъп до втория елемент на точковата двойка, а в случая на списък – до подсписъка, образуван от всички елементи на аргумента без първия.

Обръщението към функцията CAR има следния вид:(CAR арг).

То представлява списък с първи елемент името на функцията и втори елемент – аргумента на тази функция. Вижда се, че функцията CAR има само един аргумент и той трябва да е точкова двойка. От друга страна списъкът представлява частен случай на точкова двойка, следователно функцията може да се прилага и към списъци. При това обичайното използване на тази функция е именно със списъци. Важно е да се отбележи, че атомите не са точкови двойки и функцията не може да се прилага към атоми. При изпълнението на CAR първоначално се пресмята стойността на аргумента, след което функцията се прилага върху така получената стойност, като “отделя” първия елемент на точковата двойка.

Пример: нека имаме точковата двойка X -> (Y . Z). Тогава (CAR X) -> Y.В редица случаи разсъжденията относно изпълнението на функциите и

пресмятането на изразите ще бъдат представени графично по начина, даден на фиг.8.

(CAR X) -> Y

(Y . Z)

Y Фиг. 8

В ЛИСП процесът на пресмятане на стойността на аргумента се нарича оценяване, а самата стойност– оценка. Прилагането на функцията върху оценката на

14

Page 15: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

аргумента се нарича апликация на функцията. Резултатът се нарича оценка на обръщението към функцията.

Това дава възможност при програмирането на ЛИСП да се избегнат многократните присвоявания на стойности на една променлива и оттук по-висока степен на надеждност и вярност на програмата, също така да се прилагат автоматични средства за проверка на програмата.

По подобен начин се определя и функцията CDR: тя също има един аргумент, работи с точкови двойки, в частност списъци, но не и атоми, и осъществява достъпа до втория елемент на точковата двойка (вж. фиг. 9).

(CAR X) -> Z

(Y . Z)

Z Фиг.9

Важно е да се отбележи, че в ЛИСП функциите не променят стойностите на аргументите. При оценяването на аргументите тези стойности само се копират, без да се правят в тях някакви изменения.

Имената на функциите CAR и CDR са съкращения съответно от: Contents Address Register и Contents Decrement Register и са се запазили по исторически причини, които са свързани с първата реализация на езика за машината IBM 704.

На фиг.10. е показано как се прилагат двете функции върху точкова двойка X -> (А . БУКВА).

(CAR X) -> А (CDR X) -> БУКВА

(А . БУКВА) (А . БУКВА)

А БУКВА Фиг. 10.

Не трябва да се записва вместо (CAR X) израза (CAR (A . БУКВА)) или вместо (CDR X) израза (CDR (A .БУКВА), тъй като интерпретаторът ще разглежда израза в скоби (А . БУКВА) като обръщение към функцията с име А и аргумент стойността на БУКВА и ще даде или съобщение за грешка (ако такава функция не съществува), или погрешен резултат. Или накратко:

ЗАБРАНЕНО Е ЗАМЕНЯНЕТО НА АРГУМЕНТА С НЕГОВАТА СТОЙНОСТ!Сега ще видим как се прилагат функциите CAR и CDR към списъци, което е и

най-честото им използване.Ако е даден списъкът X -> (A B), то на фиг. 11. се вижда, че CAR от списъка

дава първия елемент на списъка, а CDR от списъка – списък без първия елемент, т.е. “премахва първия елемент на списъка.

15

Page 16: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(CAR X) -> А (CDR X) -> (B)

(А B) ≡ (A . (B . NIL)) (А B) ≡ (A . (B . NIL))

А (B . NIL) ≡ (B) Фиг. 11.Нека е дадено: A1 -> ERR1; A22 -> ( ). Да се опитаме да пресметнем:(CAR A1), (CAR A22), (CDR A1), (CDR A22):(CAR A1)->ERROR Не може да се пресмята CAR от атом!(CAR A22)->ERROR В DrScheme ( ) се разглежда като атом; или () В PC Scheme () се разглежда като празния списък.(CDR A1)->ERROR Не може да се вземе CDR от атом!(CDR A22)->ERROR В DrScheme ( ) се разглежда като атом; или () В PC Scheme () се разглежда като празния списък.

И така основните характеристики на функциите CAR и CDR са:а) Това са функции на един аргумент, работят с точкова двойка, в частност със

списъци, но в никакъв случай с атоми.б) Функцията CAR извлича първия елемент на точкова двойка, в частност на

списък.в) Функцията CDR извлича втория елемент на точкова двойка или “изтрива” от

списъка първия му елемент.

Примери1.Нека [X] е (A B C). Резултатите са показани на фиг. 12.

(CAR X) -> А (А B C) ≡ (A . (B . (C . NIL))) А (CDR X) -> (B C)

(А B) ≡ (A . (B . (C . NIL)))

(B . (C . NIL)) ≡ (B C)

Фиг. 12.

Не трябва да се пише (CAR (A B C)), защото транслаторът ще разглежда списъка като обръщение към функция с име A. Допуска се обаче следния запис: (CAR '(A B C)). Тук “'” представлява съкратено означение на функцията QUOTE, която дава като резултат своя аргумент. Това е една важна функция, която ще разгледаме подробно по-късно.

2.Нека [X] е (A). На фиг.13 е показано действието на функциите CAR и CDR. В този случай се вижда, че резултатът от прилагането на функцията CDR е празния списък.

16

Page 17: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

3.(CAR X) -> А (CDR X) -> NIL ≡ ( )

(А . NIL) (А . NIL)

А А Фиг. 13.4.Нека стойността на РЕЧНИК е: ((БУК . ДЪРВО) (ДВЕ . ЧИСЛО) (КОШ . СЪД))Елементите на списъка РЕЧНИК са точкови двойки, състоящи се от по-частно понятие (т.е. вид) и по-общо понятие (т.е. род). Да се напише израз, пресмятането на който да дава ЧИСЛО. Фиг. 14 представя търсения израз.(CDR (CAR (CDR РЕЧНИК))) -> (ЧИСЛО)

((БУК.ДЪРВО)(ДВЕ.ЧИСЛО)(КОШ. СЪД))

((ДВЕ . ЧИСЛО) (КОШ . СЪД))

(ДВЕ . ЧИСЛО)

(ЧИСЛО) Фиг. 14Нека разгледаме израза (CDR (CAR (CDR X))). За удобство се допуска съкратения запис (CDADR X), т.е. (CDR (CAR (CDR X))) ≡ (CDADR X).Ето още един такъв пример: (CDR (CAR (CAR (CDR X)))) ≡ (CDAADR X). Трябва да се отбележи, че в някои реализации броят на съкращенията е ограничен.

6. Функцията CONSФункцията CONS (съкращение от CONStruct) е предназначена за конструиране

на точкови двойки и списъци. Тя е двуаргументна.Обръщението към нея изглежда по следния начин: (CONS арг1 арг2)

Аргументите на CONS са S-изрази. В резултат на прилагането на функцията се получава точкова двойка от двата аргумента в противоположност на функциите CAR и CDR, които извличат елементите на точковите двойки. Ето как може да се запише това нагледно: Нека [Y] е y, [Z] е z, където y и z са S-изрази. Тогава: (CONS Y Z) -> (y . z).

Например, ако [Y] е РЕД и [Z] е ДУМА, то функцията ще даде (РЕД . ДУМА), както е показано на фиг. 15.

(CONS Y Z) -> (РЕД . ДУМА)

17

Page 18: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

РЕД ДУМА

(РЕД . ДУМА) Фиг. 15Примери:4.Нека [X] е (y . z). Тогава от израза на фиг.16. се вижда, че функцията CONS е в известен смисъл обратна на функциите CAR и CDR.

(CONS (CAR X) (CDR X)) -> (y . z)

(y . z) (y . z)

y z

(y . z) Фиг. 16.5.Нека [Y] е РЕД и [Z] е ДУМА. Да се пресметне: (CONS Y (CONS Z NIL))Резултатът е даден на фиг.16. С помощта на този пример виждаме, че посредством функцията CONS могат да се конструират не само точкови двойки, но и списъци.(CONS Y (CONS Z NIL)) -> (РЕД ДУМА)

ДУМА NIL

РЕД (ДУМА . NIL) ≡ (ДУМА)

(РЕД . (ДУМА . NIL)) ≡ (РЕД ДУМА) Фиг. 3.16

6.Нека [A] е (X Y Z) и [B] е W, където W е S–израз. На фиг. 17. е даден израз, от който се вижда, че функцията CONS може да добавя елементи в началото на един списък или да влага списъци един в друг.(CONS B A) -> (W X Y Z)

W (X Y Z)

(W . (X Y Z)) ≡ (W X Y Z)

Фиг. 17

Накратко: дотук видяхме, че чрез функцията CONS може:а) да се построяват точкови двойки;

18

Page 19: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

б) да се конструират списъци;в) да се добавя елемент отпред в списък и да се влагат списъци един в друг.

ПРАВИЛО:

Нека L е–израз. Тогава са в сила:

(CAR (CONS (CAR L) (CDR))) ≡ (CAR L)

(CDR (CONS (CAR L) (CDR))) ≡ (CDR L) (CONS (CAR L) (CDR)) -> [ L]

7. Функцията SETQ. (SET! в DrScheme и в PC Scheme)

Всяка променлива се характеризира с име и стойност. Присвояването свързва името със стойността. Следователно действието присвояване означава променливата да получи стойност. Ако променливата е имала стойност от по-раншно присвояване, то тази стойност на променливата се заменя с нова.

В ЛИСП това става с помощта на функцията за присвояване SETQ. Тя има два аргумента. Обръщението към тази функция изглежда така: (SETQ арг1 арг2),Където арг1 е атом, който не се оценява, т.е. арг1 е името на променливата, а арг2 е израз, който се оценява и получената оценка се разглежда като бъдещата стойност на арг1. Като оценка на изпълнението на функцията SETQ се получава оценката на арг2 и като страничен ефект на арг1 се присвоява оценката на арг2. Това е едно отстъпление от общата схема на езика – единият аргумент тук не се оценява, а му се присвоява стойност.Забележка: Атомът арг1 трябва да има предварително някаква стойност, получена например с DEFINE.

Нека разгледаме примера от фиг.18., като [Y] е РЕД и [Z] е ДУМА. Тогава в резултат от изпълнението на функцията SETQ за оценка на обръщението се получава точковата двойка (РЕД . ДУМА). Това ще е и стойността на аргумента X след изпълнението на функцията.

(SETQ X (CONS Y Z)) -> (РЕД . ДУМА)

РЕД ДУМА

(РЕД . ДУМА)

(РЕД . ДУМА) Фиг. 18

На фиг. 19 е даден още един пример, в който АЗБУКА има стойност (A B C … X Y Z). В този случай стойността на аргумента M и оценката на обръщението ще е списъка (A B).

(SETQ M(CONS(CAR АЗБУКА)(CONS(CADR АЗБУКА)NIL)))->(A B) (A … Z) (A … Z)

19

Page 20: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(B … Z)

B NIL

A (B . NIL)

(A . (B . NIL)) ≡ (A B)

(A B) Фиг. 19

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

8. Апликативност и функционалностЕдна от основните цели при създаването на езика ЛИСП е била да се създаде

основа на математическата теория на изчисленията. Това се изразява с факта, че главна роля в ЛИСП имат понятията функция, апликативност и оценка на израза. Да разгледаме тези понятия в езика ЛИСП. Изпълнението на програма на ЛИСП означава изпълнението на редица функции, както вградени, така и дефинирани от потребителя. Резултатите, по правило, представляват стойностите на изчислените функции. Под апликация се разбира прилагането на функцията към аргументите, които от своя страна предварително се оценяват, т.е. те могат да бъдат променливи, имащи своя стойност, а могат и да са обръщения към функции. Това дава възможност при програмирането на ЛИСП да се избегнат многократните присвоявания на стойности на една променлива и оттук по-висока степен на надеждност и вярност на програмата, а също така да се прилагат автоматични средства за проверка на програмата.

И така програмата се състои от обръщения към функции и нейното изпълнение представлява оценка на обръщения към функции. Или:

ОЦЕНКА НА ОБРЪЩЕНИЕ КЪМ ФУНКЦИЯ означава:1. ОЦЕНКА НА АРГУМЕНТИТЕ;2. АПЛИКАЦИЯ НА ФУНКЦИЯТА ВЪРХУ ОЦЕНЕНИТЕ

АРГУМЕНТИ.

Поради това езикът ЛИСП е представител на функционалните езици, като има и някои изключения от принципите на чисто функционалните езици. Това са функциите за присвояване - SETQ, LET, и др. (вж. гл.7), които само условно могат да се нарекат функции.

ЛЕКЦИЯ 3 ЛЕКЦИЯ 3

20

Page 21: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ФУНКЦИИ ПРЕДИКАТИ И УСЛОВНИ ИЗРАЗИ.Функцията NULL?. Функцията ATOM?. Функцията EQ?. Функции за условие COND. Функции за условие IF.

Функциите предикати проверяват дали е изпълнено някакво условие. В езика ЛИСП те се използват при съставяне на условни изрази.Техните оценки са или атома #Т (#t в DrScheme), за истина, т.е. при изпълнено условие или атома NIL(#f в DrScheme;() в PC Scheme)- за лъжа, т.е. когато условието не е изпълнено. Ще разгледаме най-простите предикати, които проверяват дали един S-израз е празният списък, дали един S-израз е атом и дали два атома са еднакви

1. Функцията NULL?

Тази функция извършва проверка за празен списък. Тя е едноаргументна и обръщението към нея изглежда така:

(NULL? арг)Аргументът арг е израз. Ако неговата стойност е NIL, тогава оценката на обръщението е #Т. Във всички останали случаи тя е NIL.

Тази функция има още едно име. То е NOT, което напомня логическото отрицание. Наистина, ако аргументът на функцията има стойност #Т, то резултатът е NIL, ако аргументът има стойност NIL, то резултатът е #Т .

И така двете обръщения (NULL? A) и (NOT A) са еквивалентни.Важно е да се отбележи, че аргументът на функцията NULL? е израз, т.е. атом или обръщение към функция. Тази функция ще илюстрираме с няколко примера на фиг.1, като вземем предвид, че [X] е (Y . Z), [S] е (A B C), [N] е ( ) и [N1] е (( )).(NULL? (CDR X)) -> NIL, защото Z ≢ ()

( NULL? NIL) -> #Т или (NULL? N) -> #Т

NIL ( )≡NIL

#Т #TНо (NULL? N1) -> NIL!!!

(( )) ≡ ()

NIL(NULL? (CADDR S)) -> #Т (A B C)

21

NIL

Z

(Y . Z)

Page 22: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(B C) (C)

NIL

#Т Фиг.1.

С помощта на функцията NULL? често се проверява дали е достигнат края на един списък, понеже края на един списък е NIL, т.е. празния списък.

2. Функцията ATOM?(няма я в Dr Scheme)

Следващата функция предикат е ATOM?. Тя извършва проверка за атом. Функцията е едноаргументна. Обръщението към нея изглежда така:

(ATOM? арг),където арг е израз, който се оценява и оценката му трябва да бъде S-израз. Ако стойността е атом, то резултатът е #Т. Във всички останали случаи резултатът е NIL. Или накратко: функцията ATOM? проверява дали стойността на нейния аргумент е атом.

Например: нека A -> (P Q) и S -> (A B C) и да разгледаме изразите на фиг.2. Във втория израз A се разглежда като атом, без да се влиза на по-ниско ниво – не се прави оценка на оценката, и е без значение, че A има стойност списък.(ATOM? A) -> NIL

(P Q)

NIL

(ATOM?(CAR S))-> #Т

(A B C)

A

#Т Фиг. 2

Също така нека A1->Nil, A11->(). Тогава:(ATOM? A1) ->#Т; Понеже NIL е атом!(ATOM? A11) -> #Т; Понеже ( ) ≡ NIL, а NIL е атом!Забележка: В Dr Scheme има предикат (list? aрг). Ако стойността е списък, то резултатът е #t. Във всички останали случаи резултатът е #f. Следователно може да се запише следната еквивалентност:(list? aрг) ≡(not (atom? aрг)). Но внимание (list? '())-> #t, т.е. () се разглежда като списък.

3. Функцията EQ?

Функцията EQ? е предикат за еквивалентност. Тя има два аргумента и обръщението към нея изглежда така:

22

Page 23: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(EQ? арг1 арг2),където арг1 и арг2 са изрази, които се оценяват. За да се изясни правилното действие на функцията, е необходимо да се кажат няколко думи за представянето на различните обекти (атоми, списъци, числа, низове и др.) в езика ЛИСП.Нека да разгледаме следните примери:(DEFINE L1 (CONS 'A '(B C)))(DEFINE L2 (CONS 'A '(B C)))(DEFINE L3 'A)(SET! L3 L2)

Ясно е, че L1, L2 и L3 имат една и съща стойност, а именно списъка (A B C). Но има една съществена разлика, състояща се в следното. За всяко конструиране на списък се заделят клетки от наличната свободна памет. Поради това, макар и да се конструира един и същ списък в първите два реда на горния пример, клетките памет, съответстващи на стойностите на L1 и L2, са различни (в ЛИСП е много важно да се знае, че не винаги обектите с едно и също външно представяне са едни и същи от гледна точка на представянето им в паметта). В присвояването на четвъртия ред на примера не се конструира нов обект, а указателят към клетките със стойността на L2 се записва като указател и към стойността на L3. По този начин L2 и L3 не само имат една и съща стойност, но тази стойност е записана в едни и същи клетки от паметта. За да се означи тази съществена разлика при използването на обектите от езика ЛИСП, ще въведем понятията физическа и логическа еквивалентност. Ще казваме, че два обекта са физически еквивалентни, ако за вътрешното им представяне се използват едни и същи клетки от паметта. В горния пример стойностите на L2 и L3 са физически еквивалентни обекти. Два обекта са логически еквивалентни, ако имат едно и също външно представяне (стойностите на L1 и L2 от горния пример). От дадената дефиниция и посочения пример се вижда, че два физически еквивалентни обекта са и логически еквивалентни. Обратното обаче не е вярно.

И така стойността на обръщението към функцията EQ е #T тогава и само тогава, когато аргументите й са физически еквивалентни обекти. Следователно:(EQ? L3 L2)->#T (EQ? L3 L1)-> NILНа фиг. 4.3 са дадени два примера, в които M -> (A B) и N -> (C A B).

(EQ? (CAR M) (CAR (CDR N))) ->#T

(C A B)

23

Page 24: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(A B) (A B)

A A

#T

(EQ? (CDR N) M) -> NIL

(C A B)

(A B) (A B)

NIL Фиг.3.

От примера се вижда, че в случая, когато аргументите на функцията са едни и същи атоми, оценката на обръщението към функцията е #T. Това е така, защото понятията логическа и физическа еквивалентност при атомите съвпадат (името на атома се използва като указател към клетките от паметта, представящи дадения атом). Следователно:(EQ? 'B 'B) -> #T(EQ? T T) -> #T (EQ? NIL NIL) ->#T(EQ? 12 12) -> #T(EQ? 12 12.0) -> NIL(EQ? 12345678900000 12345678900000)-> NIL

Физическата и логическата еквивалентност съвпада и при символите, част от целите числа (например, за Dr Scheme целите числа в интервала [-230; 230 –1]). Това съвпадение зависи от конкретната реализация на езика ЛИСП.

След като знаем действието на функцията EQ?, можем да се върнем към функцията NULL? и да определим нейното действие по следния начин: (NULL? A) ≡ (EQ? A NIL),Т.е. функцията NULL? сравнява дали стойността на аргумента е еквивалентна с атома NIL.

4.Функция за условие COND

Функцията служи за изпълнение на едно или друго действие в зависимост от определени условия. Тя има произволен брой аргументи и обръщението към нея изглежда по следния начин:

(COND арг1 арг2 … аргn),където всеки аргумент аргi има следния вид:

(<УСЛОВИЕ-i> <СЛЕДСТВИЕ-i>) за I = 1, 2, …, n,т.е. всеки аргумент е списък от два елемента. Нека означим с P елемента <УСЛОВИЕ> и с V елемента <СЛЕДСТВИЕ>. P и V са изрази, т.е. атоми или обръщения към функции.

Разписано, обръщението към функцията изглежда така:

(COND (<УСЛОВИЕ-1> <СЛЕДСТВИЕ-1>)

24

Page 25: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(<УСЛОВИЕ-2> <СЛЕДСТВИЕ-2>) … … … … (<УСЛОВИЕ-n> <СЛЕДСТВИЕ-n>) [ (else <СЛЕДСТВИЕ-n+1>)] )

(COND (P1 V1) (P2 V2) … (Pn Vn) (ELSE Vn+1))

От определението веднага се вижда, че аргументите на функцията COND са списъци от по два елемента, като първият се третира като условие, а вторият – като следствие. Изпълнението на функцията става по следния начин:1. Оценяват се последователно условията, докато се достигне първото, чиято

стойност е различна от NIL. Нека да го означим с P.2. Оценява се съответното следствие V.3. За оценка на обръщението към функцията COND се приема оценката на

последния оценен израз.Има няколко частни случая:

- ако се изчерпят всички аргументи до аргn, тогава оценката на обръщението ще бъде оценката на Vn+1 ;

- ако при последователните проверки се е получило, че стойността на израза P е различна от NIL, а съответното следствие V липсва, то за оценка на обръщението се приема стойността на P. С други думи, условието и следствието могат да съвпадат. Също така в повечето реализации на езика на мястото на V може да стои не само един израз, а последователност от изрази.И накрая важно е да се отбележи, че условията и следствията след аргi (след

удовлетвореното условие и неговото следствие) не се разглеждат.Функцията COND е едно друго отстъпление от общата схема на езика – тук не

се извършва оценка на всички аргументи.Ето една конкретна схема на обръщение към COND:

Нека [P1] е NIL и [P2] е NIL, а [P3] е различно от NIL. Тогава:(COND (P1 V1) (P2 V2) (P3 V3) (P4 V4))-> [V3]Най-напред се оценява P1. Тъй като оценката му е NIL, се преминава към следващия аргумент. Оценява се условието P2 и тъй като и то е NIL, се преминава към третия аргумент. Оценката на P3 е различна от NIL. Следва оценката на V3 и прекратяване на по-нататъшното оценяване. Оценката на функцията е [V3].А ето и един конкретен пример: (COND ((ATOM? X) (SETQ L X)) ((ATOM? Y) (SETQ L Y))).

Ако X има стойност атом, то още първото условие ще даде стойност #T, което е различно от NIL. Тогава стойността на X ще се запише в L и ще стане стойност на обръщението.

Ако стойността на X не е атом, то първото условие ще даде NIL и ще се премине към второто условие. Ако Y има стойност атом, то L ще получи стойността на Y и тя ще стане стойност на обръщението.

Ако стойността на Y не е атом, обръщението получава стойност NIL.Да разгледаме още един пример.

25

Page 26: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Нека стойността на X е списък. Да разгледаме обръщението (COND ((NULL? X) NIL) ( #T (CAR X))).С първото условие се проверява стойността на X. Ако X е празният списък, стойността на обръщението става NIL. Второто условие е безусловно твърдение, което винаги е различно от NIL (#T има стойност #T ). Следователно ще се изпълни второто следствие. Неговата стойност е първият елемент на X (който в случая не е празен списък). Този елемент става и оценка на обръщението.Накратко, тук се извършват следните действия:1.Проверка за празен списък.2.Ако списъкът не е празен, се взема първия му елемент.По-късно ще видим как с помощта на тази схема, комбинирана с (CDR X) и поставена в цикъл, може да бъде обходен един списък.И накрая един последен пример. Нека стойността на X е S–израз. Дадено е обръщението: (COND ((NULL? X) NIL) ( #T ))Тогава, ако стойността на X е NIL, то първото условие дава стойност #T и стойността на обръщението NIL. Ако стойността на X не е NIL, тогава първото условие дава стойност NIL и се разглежда второто условие, което е безусловно твърдение. То има стойност #T и тя става оценка на обръщението, тъй като в този случай имаме съвпадение на условие и следствие.

Накратко, това е проверка дали един израз е или не е NIL.

5. Функция за условие IF

Функцията служи за изпълнение на едно или друго действие в зависимост от определени условия. Обръщението към нея изглежда по следния начин: (IF <УСЛОВИЕ> <СЛЕДСТВИЕ> <АЛТЕРНАТИВА>)- ако <УСЛОВИЕ> е истина, то се оценява <СЛЕДСТВИЕ>, иначе <АЛТЕРНАТИВА> и това е оценката на функцията. Забележка: Разликата между IF и COND е, че <СЛЕДСТВИЕ> и <АЛТЕРНАТИВА> в IF са точно от един израз. А ето и един конкретен пример: (IF (> C 0) 'ПОЛОЖИТЕЛНО 'НЕПОЛОЖИТЕЛНО)Ако стойността на C е положително число, то (> C 0) е #T и се оценява <СЛЕДСТВИЕ> и неговата оценка е оценка на функцията, в противен случай се оценява <АЛТЕРНАТИВА> и това е оценка на функцията.Примери:1.Да се провери дали стойността на BIT е елемент на списъка TOP, който има три елемента.Решение:(COND ((EQ? BIT (CAR TOP)) #T) ((EQ? BIT (CADR TOP)) #T) ((EQ? BIT (CADDR TOP)) #T))

2.Усложнен вариант на горната задача: да се провери дали BIT се съдържа измежду атомите в списъка, получен при изпълнението на:(SETQ TOPL ‘((MONEY ABBA) (MONEY PINK_FLOYD) (GIRL BEATLES)))Решение:

26

Page 27: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(COND ((EQ? BIT (CAAR TOPL)) #T) ((EQ? BIT (CADAR TOPL)) #T) ((EQ? BIT (CAADR TOPL)) #T) ((EQ? BIT (CADADR TOPL)) #T) ((EQ? BIT (CAADDR TOPL)) #T) ((EQ? BIT (CAR(CDADDR TOPL)) #T)) ; заради ограничението в броя на съкращенията.

3.Нека е даден същият списък. Да се определи дали SONG се съдържа като първи елемент на някой подсписък и в случай на успех да се даде втория елемент.Решение:(COND ((EQ? SONG (CAAR TOPL)) (CADAR TOPL)) ((EQ? SONG (CAADR TOPL)) (CADADR TOPL )) ((EQ? SONG (CAADDR TOPL)) (CAR(CDADDR TOPL)))

4.Нека L е атом или списък. Да се провери дали L е атом, празен списък, списък от един елемент, списък от два елемента, списък от три елемента или списък от повече от три елемента и да се получат съответно стойностите -1, 0, 1, 2, 3 и N.

5.Нека SING има стойност атом. Да се провери дали стойността на SING е I, F, D, E или друга и да се присвои на A съответно стойност INTEGER, REAL, EXP, EXP и OTHER. Да се напише и съответната програма на C.

6.Да разгледаме израза:(COND ((NULL? (ATOM? L) ) (NULL? (NULL? NIL))) ((EQ? (ATOM? L) (NULL? NIL)) (ATOM? L )))Нека стойността на L е последователно NAM, (N A M) и NIL. Да се оцени израза за всяка стойност на L.Решение:

В първия случай: първото условие дава стойност NIL, а второто - #T. Неговото следствие има стойност #T (NAM е атом). Тогава оценката на израза е #T.

Във втория случай: първото условие дава стойност #T (в този случай L има стойност списък, следователно проверката за атом дава NIL, а проверката за NIL - #T). Тогава оценката на израза е стойността на първото следствие, която е NIL (проверката за NIL дава стойност #T, а следващата проверка за NIL - стойността NIL).

В третия случай: NIL е атом. В първата проверка (ATOM? L) дава стойност #T, а (NULL? (ATOM? L)) дава стойност NIL. Тогава се разглежда второто условие. То има стойноста #T и тогава оценката на обръщението е стойността на второто следствие, което е #T, тъй като NIL в случая е атом.

ЛЕКЦИЯ 4

СТРУКТУРА НА ПРОГРАМИТЕОбща структура на програмите в ЛИСП. Функцията QUOTE. Функцията APPEND. Функцията LIST. Функцията EVAL. Функцията REVERSE.

27

Page 28: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

1. Обща структура на програмите на ЛИСП

Както се вижда от досегашните разглеждания, операторите в ЛИСП представляват вложени едно в друго обръщения към функции. При тези вложения на различни нива, първото ниво се нарича най-високо и в различните интерпретатори се означава по различен начин. За целта се използва и специален знак в края на израза (например клавиша Enter от клавиатурата на компютъра), или се използва изравняването по брой на затварящите с отварящите скоби.

Като специален знак за край на израз на най-високо ниво ние ще използваме кавички (“) след последната затваряща скоба. Така означения израз ще наричаме “завършен израз” или “израз от най-високо ниво”. Завършеността на израза означава, че той е готов да бъде изпълнен от интерпретатора.

Определението на израз на най-високо ниво може да се запише накратко по следния начин:

<ИЗРАЗ НА НАЙ-ВИСОКО НИВО> е <ИЗРАЗ>”,т.е. атом или обръщение към функция, но не и точкова двойка.Поредицата изрази на най-високо ниво в ЛИСП се нарича програма. Изразите от програмата се изпълняват в режим на интерпретация по реда на записването им. След пресмятането на стойността на даден израз тя се отпечатва и/или се извежда на екрана на компютъра.

В рамките на едно изпълнение на поредицата изрази стойностите, присвоени на променливите във вече пресметнатите изрази, се запазват, т.е. в една програма променливите са глобални. Тези променливи могат да се използват и променят в следващите изрази нa най-високо ниво.Важно е да се знае:1.Чрез задаване на различни опции могат да се искат някои услуги от системата.2.Съществуват функции за въвеждане и извеждане, като те могат да са както на най-високо ниво, така също и вложени на по-ниско ниво.3.Освен в режим на интерпретация може да се работи и в режим на компилация. Това става чрез специална функция COMPILE. Компилираните програми са много по-бързи. В режим на компилация обикновено се работи, когато се знае, че програмата е вярна, и когато тя ще се изпълнява многократно.

2.Функцията QUOTE

В редица случаи е удобно да се използват константи, без те да са били предварително присвоени на някакъв атом. Т. е. да цитираме S-израз (атом, списък или точкова двойка), без да трябва предварително да се оценява. За това служи функцията QUOTE. Тя е едноаргументна и обръщението към нея е: (QUOTE арг),където арг е S-израз, т.е. атом, точкова двойка или списък. Аргументът арг не се оценява (ето защо той може да бъде произволен S-израз). Оценката на обръщението е самият аргумент арг, т.е. функцията QUOTE връща своя аргумент като стойност на обръщението.

Нека разгледаме няколко примера.1. Нека A е атом. Тогава (QUOTE A )-> A, но не [A] (стойността на A) – аргументът

не се оценява!!!(QUOTE (CAR X)) -> (CAR X)2.Предвиден е и кратък запис на обръщението (QUOTE A) към функцията QUOTE и той изглежда така: 'A, т.е. (QUOTE A) ≡ 'AТогава горните примери могат да се запишат по следния начин:'A -> A

28

Page 29: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

'(CAR X) -> (CAR X)3.Нека X -> (A B C). Тогава (CAR X) -> A (вж. фиг. 5.1). Но обръщението (CAR 'X) е некоректно, защото X ще се разглежда в случая като атом.

Знае се, че в записа (CAR (A B C)) аргументът на функцията CAR се разглежда като обръщение към функция с име A и аргументи стойностите на B и C. Ако искаме (A B C) да се разглежда като списък, тогава правилният запис е (CAR '(A B C)) и стойността на това обръщение е A (вж. фиг. 1. и 2). От тук се вижда, че с помощта на функцията QUOTE се разграничават двете възможни употреби на списъците в ЛИСП – като обръщение към функция и като структури данни.

(CAR X) -> А (CAR '(A B C)) -> А

(А B C) (А B C)

А А Фиг. 1. Фиг.2.

Нека сега видим по какъв начин може да се получи (A B C) за оценка на обръщението (SETQ M X).

Ако запишем (SETQ M (A B C)), списъкът (A B C) ще се тълкува като обръщение към функцията с име A. Ако обаче запишем (SETQ M '(A B C)), ще получим искания резултат (A B C), т.е. (SETQ M X)≡ (SETQ M (A B C)) -> (A B C), като X -> (A B C).Нека сега за същата стойност на аргумента X е дадено следното обръщение:(QUOTE (QUOTE (CAR X))) -> (QUOTE (CAR X)),т.е. стойността на обръщението е (QUOTE (CAR X)).

Следователно оценява се само най-външното ниво на вложените функции QUOTE.

При повечето функции в ЛИСП се извършва оценяване на аргумента. Затова при влагане на функции, се навлиза в дълбочина по време на изпълнението. Но при функцията QUOTE такова навлизане няма, защото аргумента й не се оценява.Ето няколко примера на такива вложения:'' (CAR X) -> '(CAR X)''' (CAR X) -> ''(CAR X)' (QUOTE X) -> (QUOTE X)Но (QUOTE (QUOTE (CAR X))) -> A не е вярно!

Има още една подобна функция в ЛИСП: (QUASIQUOTE арг), където арг е S-израз, т.е. атом, точкова двойка или списък. Аргументът арг не се оценява (ето защо той може да бъде произволен S-израз). Ако арг не е списък- QUASIQUOTE ≡ QUOTE. Иначе, ако елементите са предшествани от , се оценяват и се извежда оценката, а ако има ,@- ако оценката е списък той се разгражда. Предвиден е и кратък запис на обръщението (QUASIQUOTE A) към функцията QUASIQUOTE и той изглежда така: `A, т.е. (QUASIQUOTE A) ≡ `A(DEFINE A 8) ; на а се дава стойност 8(DEFINE B (- A 2)) ) ;на в се дава стойност ;8-2=6`A->A`(A B)->(A B)

29

Page 30: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

`(,A ,B)->(8 6)`(X= ,A)->(X= 8)

3.Функцията APPEND

Сега ще разгледаме една функция, която обединява два списъка. Това е функцията APPEND. Тя има два аргумента. Обръщението към нея има следния вид:(APPEND арг1 арг2),където арг1 и арг2 са изрази, които се оценяват. Техните стойности трябва задължително да са списъци. В резултат от изпълнението на функцията APPEND се получава нов списък, който съдържа елементите на списъците, които са стойности на арг1 и арг2, т.е.:

(APPEND арг1 арг2) -> (<ЕЛЕМЕНТИ НА [арг1]><ЕЛЕМЕНТИ НА [арг2]>)

Но не се получава списък от двата елемента [арг1] и [арг2].Ако арг1 има стойност празния списък, тогава стойността на обръщението е

стойността на арг2. Ако арг2 има стойност празния списък, то стойността на обръщението е стойността на арг1. Ако и двата списъка са празни, получава се празен списък.Това определение се илюстрира на фиг.3, т.е. единият списък се копира, след което се разрушава указателят за край на копирания списък, като на негово място се поставя указател, сочещ началото на другия списък. Вижда се, че изпълнението на APPEND изисква доста памет и време поради преписването на първия списък. Ето защо тази функция е подходяща за работа с малки списъци, тъй като при големи списъци има опасност от недостиг на памет.[A1] [A2]

копира се [A1]

Фиг.3

На фиг.4 са разгледани два примера, като в първия се смята, че S-> (A B C). Във втория пример се вижда, че списъците аргументи се разграждат, но подсписъците в тях се запазват.

(APPEND S S) -> (A B C A B C)

(A B C) (A B C)

(A B C A B C)

30

Page 31: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(APPEND ’(A B C) ’(M (H P)))->(A B C M (H P)) (A B C) (M (H P))

(A B C M (H P)) Фиг. 5.4 Нека S е произволен S-израз. Следният израз поставя този S-израз в края на произволен списък L:(APPEND L (CONS S NIL))

Необходимо е да се прави разлика между функциите CONS и APPEND. Докато с CONS можем да добавим елемент в началото на списък, то с APPEND

добавяме елементите на един списък в началото на друг списък. Освен това при функцията APPEND се използва повече памет, отколкото при CONS.

4.Функцията LIST

Функцията LIST е функция на произволен брой аргументи. Тя също обединява списъци, но по друг начин. Обръщението към нея изглежда така:

(LIST арг1 арг2 … аргn),където аргi са изрази, които се оценяват (I = 1,2,…,n ). Оценките им могат да бъдат произволни –изрази, т.е. атоми, точкови двойки, списъци или обръщения към функции. В резултат на изпълнението на функцията LIST се получава списък, чийто елементи са стойности на аргументите на функцията. Броят на елементите на новополучения списък е равен на броя на аргументите на функцията. Стойностите на аргументите не се разграждат, както това става при функцията APPEND. Те само се обединяват, без да се сливат (вж. фиг. 5 ), т.е.

(LIST арг1 арг2 … аргn)->([арг1][арг2] … [аргn]), . . . . … .

[A1] [A2] [An]Фиг. 5.

Важно е още, че функцията LIST не изисква толкова време и памет, колкото функцията APPEND. Тя в известен смисъл е аналог на функцията CONS, пригоден за поставяне на повече от един елемент в началото на празния списък.На фиг.6. са дадени няколко примера, при които P->A, O->(B C), M->H, A->CAR и B -> X.

(LIST P O M) -> (A (B C) H)

A (B C) H

(A (B C) H)

31

Page 32: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(LIST 'P 'O 'M) -> (P O M)

P O M

(P O M)

(LIST A B) -> (CAR X)

CAR X

(CAR X) Фиг. 6.Резултатът от първия пример е еднакъв с резултата от следния израз: (LIST 'A '(B C) 'H)При сравняването на първия и втория пример се вижда още едно приложение на функцията QUOTE. Чрез нея в процеса на изпълнение на програмата могат да се конструират обръщения към функции. Изпълнението на такива конструирани обръщения става чрез специална функция, която ще разгледаме по-долу.

5.Функцията EVAL

Тя е функция на един аргумент. Обръщението към EVAL е: (EVAL арг),където арг е израз, който при обръщение към EVAL се оценява два пъти. При изпълнението на функцията EVAL първоначално се оценява арг, като се получава стойност на арг. След това вече стойността на арг се оценява още един път. Тази последна оценка е и стойността на обръщението към функцията EVAL.

На фиг. 7. е показано изпълнението на един израз, в който се съдържа функцията EVAL. В него имаме: A -> CAR, B ->X и X -> (C D).(EVAL (LIST A B)) -> C

CAR X

(CAR X) (C D) C C Фиг.7. На фиг.8. са дадени още няколко примера, при които M -> H, H -> (P O), X -> (A B C) и A -> (P Q). Вместо (EVAL (QUOTE M)) при втория пример може да се запише (EVAL 'M) или още по-кратко M.

С други думи, за интерпретатора е в сила M ≡ (EVAL 'M).

1)(EVAL M) -> (P O)

H

(P O)

32

Page 33: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

2)(EVAL (QUOTE M)) -> H

M

H

3)(EVAL '(CAR X)) -> A

(CAR X)

(A B C)

A AНо (EVAL '(CAR X)) -> (P Q) е грешно!!!

(A B C) A A

(P Q) Фиг.8.

От последните два примера следва, че (EVAL (QUOTE <ИЗРАЗ>) води до пресмятане на ИЗРАЗ. Следователно интерпретаторът прилага функцията EVAL към 'ИЗРАЗ за всеки израз на най-високо ниво. От това следва, че пример 1 може да се запише по следния начин:(EVAL '(EVAL M)), т.е. (EVAL M) ≡ (EVAL '(EVAL M))

По същия начин при третия пример нещата се свеждат до оценяването на CAR.На фиг. 9. е даден един последен пример, при който A -> X и X -> C.

(EVAL '(EVAL A)) -> C (EVAL A) X C C Фиг. 9. Във връзка с този пример може да отбележим, че(EVAL '(EVAL A)) ≡ (EVAL A)

6.Функцията REVERSE

Тази функция сменя реда на елементите на списък. Има един аргумент. Обръщението към нея е следното:

(REVERSE арг),където арг е израз, който се оценява. Неговата стойност трябва задължително да бъде списък. В резултат на изпълнението на функцията REVERSE се получава списък от подредени в обратен ред елементи на първоначалния списък, т.е. ако списъкът (A1 A2

33

Page 34: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

… An) е стойност на атома A, тогава стойността на обръщението (REVERSE A) ще бъде списъка (An … A2 A1). Ако стойността на A е празният списък, то и стойността на обръщението към REVERSE ще даде празния списък. На фиг. 10. е даден един пример, в който стойността на S е (A B (C H E)).(REVERSE S) -> ((C H E) B A)

(A B (C H E))

((C H E) B A) Фиг.10. Вижда се, че функцията REVERSE обръща реда на елементите от най- високо ниво, а подсписъците се запазват непроменени.

34

Page 35: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИЯ 5ДЕФИНИРАНЕ НА ФУНКЦИИ.

Функция.Локални и глобални променливи. Дефиниране на функции в ЛИСП. Рекурсия. Обща схема на рекурсивна дефиниция на функция.

1. Функция.

1.1.Понятие за функция

В математиката с функцията се изобразява едно множество в друго. Записва се така : Y = F (x)

На х от дефиниционното множество (Domain) се поставя в съответствие Y от множеството на стойностите (range) за функцията F.

Може да се запише: Y = F (x) F (x) → Y F: x →

Функцията може да има всякакъв брой аргументи, а функция без аргументи има постоянно значение.

Примери за функции:

abs( -3 ) --> 3 абсолютна величина.+ ( 2 , 3 ) --> 5 сумиранеunion ( ( a , b ), ( c , b ) ) --> ( a , b , c ) обединение на множества.количеството _на _буквите ( дума ) --> 5

35

Page 36: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

1.2. Типове аргументи и функции

Функцията в общия случай се задава като изображение на няколко множества в множеството от значения(стойности).

Може да се запише така :

F (x,y) → ZF: A× B→C

Това е функция от два аргумента: първият х принадлежи на А, вторият у принадлежи на В, стойността z принадлежи на С. В този случай говорим, че аргументите и стойностите имат различни типове.

Пример:

F: A× B→C

ЯНУАРИ1

1януари

36

Page 37: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

1.3. Префиксна нотация

В математиката В Лисп

В математиката е приета префиксната нотация, в която името на функции е пред аргументите и се затваря в скоби.

В Лисп за запис на аритметически изрази и функции се използва единна префиксна форма на записа, в която името на функцията или действието е пред аргументите и се записва вътре в скобите.

f ( x )g ( x , y )h ( x , g ( y , z ) )

( f x )( g x y )( h x ( g y z )

в аритметическите изрази се използва инфиксния запис :

x + yx - yx * ( x + z )

( + x y )( - x y )( * x ( + x z ) )

Предимствата са :

• Опростява се синтактическия анализ на изразите, т.к. чрез първия символ на текущия израз системата с каква структура ще работи

• Става възможно да се записва функцията под формата на списък, т.е. данните (списъците) и програмата (списъка) се представят по еднообразен начин.

1.4. Диалог с интерпретатора на ЛИСП

Транслаторът на Лисп работи по правило в режим на интерпретатор.

Read-eval-print (REP) цикъл

loop { read evaluate print)

В Лисп отначало се чете (read), след това се изчислява(evaluate) стойността на функцията и се извежда стойността (print).

Пример :

* ( + 2 3 ) 5

37

Page 38: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

1.5 Йерархия на извикванията

Във въвежданата функция може да се включват функционални бод изрази :

* (* ( + 1 2 ) ( + 3 4 ))21

2.Локални и глобални променливи

Нека е дадена функцията F и нека в тялото й е дефинирана друга функция (чрез DEFUN), която да наречем G. В тялото на G могат да се използват както нейните формални параметри, така също и някои други променливи. При обръщение във F към G формалните параметри се заместват с фактически. Те се използват вътре в G, като техните стойности могат да се променят (например чрез SETQ). При излизане от процедурата G те възстановяват стойностите се, които са имали преди обръщението към G. Такива параметри са локални променливи. Вътре в тялото на F могат да се използват и други променливи, които не са нито формални, нито фактически параметри. Може да ги разделим на две категории. Едните са достъпни само в рамките на дефинираната функция и поради това са също локални променливи (такива променливи се дефинират при използване на функцията LET, разгледана в следващата глава). Другите са достъпни във всички дефинирани функции и поради това се наричат глобални променливи. Промяната на стойностите на глобалните променливи не е препоръчителна. По-добре е връзката между функциите да става посредством механизма на формално-фактическите параметри.

2.Дефиниране на функции в ЛИСП

Съществена част от интерпретатора на ЛИСП са вградените функции. Те са силно оптимизирани по време и памет. Някои от тях са написани на ЛИСП, други – на АСЕМБЛЕР. Някои от тях: |x|-(abs x), sinx-(sin x), cosx-(cos x), x -(sqrt x), xy-(expt x y), ex-(exp x), ln(x)-(log x), целочислено деление n на k (quotient n k), остатък при целочислено деление на n на k - (remainder n k), отрязва дробната част-(truncate x), закръгля до най-близкото цяло(round x), (random n)- генерира случайно число между 0 и n,(runtime)- връща колко е работила системата в милисекунди. Ползва се разликата между резултата преди началото и в края на функцията.

Освен това потребителят може сам да дефинира функции, ако вградените не са достатъчни за решаване на задачата му. Тези функции могат след това да се използват наравно с вградените. За разлика от редица други езици, в ЛИСП дефинираните функции могат да не се компилират, а да се интерпретират по време на изпълнението на цялата програма.

Дефинирането на функции става чрез функцията DEFUN. Тя е функция на три аргумента и обръщението към нея има следния вид:

(DEFUN арг1 арг2 арг3),

38

Page 39: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(DEFINE (арг1 арг2 )арг3 ) (в DrScheme и PC Scheme)където арг1, арг2 и арг3 не се оценяват. арг1 е атом, представлява името на дефинираната функция. арг2 е редица от атоми P1 P2 … Pn, която представлява формалните параметри на функцията. арг2 може да е празна редица, тогава функцията е без формални параметри (в този случай DEFINE играе роля на присвояване в „традиционните” езици за програмиране). арг3 е израз, който представлява тялото на функцията. В тялото на функцията е допустима рекурсия. Формалните параметри трябва да фигурират вътре в тялото на функцията.

Обръщението към функцията DEFUN предизвиква дефиниране на функция, т.е. записване на името й в списъка на дефинираните функции, а освен това предизвиква и известна преработка на дефинираната функция. Ако дефинирането премине успешно, транслаторът извежда името на току що дефинираната функция. Ако вече е била дефинирана функция с такова име, след името транслаторът изписва и съответно съобщение, като старата дефиниция се заменя с новата.

Така дефинираната функция може да бъде използвана по общите правила за обръщения към функции:

(<ИМЕ> Q1 Q2 … Qn),където Q1, Q2, …, Qn са фактически параметри, с които се заместват формалните. Те трябва да отговарят на описанието на функцията, т.е. на ограниченията, наложени от потребителя. Фактическите параметри се оценяват и стойностите им стават стойности на формалните параметри, при което се предизвиква пресмятане на израза от описанието на функцията, т.е. на нейното тяло. Стойността на тялото ще стане оценка на обръщението към функцията.

И така при обръщение към функцията DEFUN като стойност на обръщението се получава името на дефинираната функция, а като страничен ефект – дефиниране на функция с име арг1, списък на формалните параметри арг2 и тяло арг3.

Не е необходимо потребителят да знае как е реализирана дадена функция, за да я използува. той може да я получи като черна кутия, на която подава вход и получава резултат. Възможността за дефиниране на функции позволява да се разбие задачата на подзадачи, които да се решат от различни автори. Позволено е влагане на дефиниции, но това може да стане само веднага след списъка от формални параметри на основната функция.Ето два примера: 1.Да се напише функция, която изчислява лице на триъгълник по 3 страни.(DEFINE (S A B C) (DEFINE P (/(+ A B C) 2)) (EXP (* (/ 1 2) (LOG (* P (- P A) (- P B) (- P C))))))2.Да се напише функция, която по зададено цяло число n изчислява израза 10n+1-10n . (DEFINE (IZ N ) (DEFINE D (EXP (* N (LOG 10)))) (- (+ D 1) D))

3.Рекурсия

В ЛИСП различаваме две разновидности на рекурсия – в обръщенията към функциите и в техните дефиниции.Първата разновидност е по-проста: ако например F е функция, то обръщението (F (F (F <ИЗРАЗ>))) представлява едно рекурсивно обръщение към F. То се изпълнява съгласно обичайното правило за оценяване на вложени функции – търсене отвън навътре на най-вътрешното ниво на вложение, оценяване на това обръщение, които

39

Page 40: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

след това става аргумент на по-външното обръщение, и т.н., докато се оценят всички обръщения. За да бъдат всички обръщения коректни, вътрешните обръщения трябва също да бъдат изрази.

На фиг.1. е даден един пример на рекурсивно обръщение.(CDR(CDR(CDR(QUOTE (A B C D )))))->(D)

(A B C D)

(B C D)

(C D)

(D) Фиг. 1.

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

Следва пример за рекурсивна дефиниция на функцията REVERSE.Нека е даден списък S -> (A1 A2 A3 A4). Ако предположим, че A2, A3 и A4 са вече наредени в искания ред в някакъв списък, то трябва да поставим (CAR S) в края на този списък, например чрез APPEND. Нареждането на A2, A3 и A4 може да стане чрез (REVERSE (CDR S)). По този път може да се върви, докато се стигне до (CDR ’(A4)), което е ( ). Знаем, че (REVERSE ’()) трябва да дава стойност ( ). Тогава, като използваме тази стойност, може да се върнем обратно и да пресметнем стойността на функцията. Или: трябва да се обединят в един списък (REVERSE (CDR S)) и (CAR S) – така задачата се свежда до задачи с по-прости аргументи. При всяко такова навлизане към по-прост аргумент трябва да се проверява дали не е достигнат края на списъка, т.е. ( ) (това е най-простият случай), при което задачата се решава пряко. Така стигнахме до следната схема на функцията:1.Проверка за край: дали S е ( ). Тогава стойността на обръщението също е ( ).2.Рекурсивно обръщение: аргументът се опростява, докато се стигне до най-простия случай.

40

Page 41: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

В транслатора има вграден механизъм за изпълнение на рекурсивни функции: при всяко рекурсивно обръщение получените до момента резултати се поставят в стек, докато се достигне до директно пресмятане, при връщането обратно запазените в стека междинни резултати се извличат обратно. А ето и самата функция(DEFINE (REVERSE S) (COND ((NULL? S) ()) (ELSE (APPEND (REVERSE (CDR S)) (CONS (CAR S) ()) ))))Ако стойността на S е (), тогава първото условие получава стойност #T, а стойността на обръщението към COND става #F.

Ако стойността на S не е (), тогава първото условие получава стойност #F и се разглежда втората възможност. Тук става обединението на частично наредения списък с (CAR S).

На фиг.2. е показан рекурсивният процес при изпълнението на обръщението към функцията REVERSE при стойност на S (A B C D).

Ниво на рекурсия

I II III IV V

Аргумент на

REVERSE

(A B C D)

(B C D)

(C D) (D) NIL

Резултат от REVERSE

?(D C B A)

?(D B C)

?(D C)

?(D)

?(D)

Фиг.2.

При първото обръщение стойността на S е (A B C D). Стойността на обръщението все още не се знае. При разглеждането на второто условие (S не е ()) става повторно обръщение към REVERSE, но с вече опростен аргумент (ниво на рекурсията ІІ). Резултатът от изпълнението също не се знае. По същия начин се навлиза и в следващите нива, ІІІ и ІV, на рекурсия, като всеки път аргументът се

(A B C D) (D C B A)

(B C D)

(C D)

(D)

( ) ( )

(D)

(D C)

(D C B)

Последователно получаване на стойностите

REVERSE

REVERSE

REVERSE

REVERSE

REVERSE

Опростяване на аргумента

Фиг.3.

41

Page 42: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

опростява. Така се стига до ниво V, където стойността на S става (). Тогава първото условие става #T и се пресмята стойността - () - на съответното условие. Тя се явява стойност на петото обръщение към REVERSE, пресметнато пряко! Оттук започва и връщането – на ІV ниво се пресмята функцията (REVERSE ’(D)) чрез APPEND с аргументи (REVERSE (CDR S)), което вече е пресметнато - () и (CONS (CAR S) ()), което е (D). По същия начин се преминава последователно през ІІІ, ІІ и І ниво на рекурсията, като на най-високото първо ниво са получава самата стойност на обръщението към функцията REVERSE – (D C B A). При междинните рекурсивни обръщения на всяко ниво на рекурсия функциите (в случая APPEND) остават неизпълнени. Те се доизпълняват, както се видя, при връщането.

На фиг.3.е даден един по-прост и нагледен начин за представяне на схемата от фиг. 2 . Възможни са няколко рекурсивни обръщения едно в друго. Тогава схемата се разклонява.

4. Обща схема на рекурсивна дефиниция на функция

Най-често рекурсивната дефиниция на една функция изглежда по следния начин:

(DEFINE (F A1 … An) - - - <условие за прост случай> - - - <рекурсивно обръщение към F> - - - <рекурсивно обръщение към F> - - - ),

където F е името на функцията, A1, A2, … , An - нейните аргументи, а с - - - са означени липсващите части от дефиницията. Естествено, отделните елементи не са разположени последователно, а са обединени посредством влагане на функции една в друга, което е основен принцип при програмирането на ЛИСП.

За правилно създаване и използване на рекурсивни дефиниции е важно да се обърне внимание на няколко основни момента:а) В тялото на функцията трябва задължително да присъства т.нар. условие за прост случай. То е свързано с проверка на определено свойство на входните аргументи и се съпровожда с явно посочване на оценката на функцията F, в случай че условието е изпълнено.б) Условието за прост случай трябва да предшествува рекурсивното обръщение към функцията. Дефинираните по този начин функции са много по-елегантни, като същевременно се избягва възможността за зацикляне при изпълнението им.в) В тялото на функцията трябва явно да присъстват изрази, които модифицират аргументите преди извършването на рекурсивното обръщение. Последователната модификация трябва да води до такива стойности на аргументите, които удовлетворяват условието за прост случай.г) В тялото на една рекурсивна функция могат да се срещат и няколко рекурсивни обръщения. Възможно е и използването на косвена рекурсия или взаимна рекурсия. Нищо не пречи в рекурсивното обръщение при дефиниране на рекурсивна функция като аргумент да стои друго рекурсивно обръщение.На всяка дефинирана функция може да се гледа както декларативно (описание на свойствата на обекта, който трябва да се намери), така и императивно (процес, който ще доведе до търсения резултат). Процес- това е абстрактно понятие, описващо

42

Page 43: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

развитието на пресмятанията във времето, т.е. преобразуването на входните данни стъпка по стъпка до получаване на резултата.Следват няколко примера за решаване на задачи чрез тези два подхода:1.Да се напише функция, която изчислява N! по зададено естествено n.

−=

=случай противен вnn

nприn

,)!1.(

0 ,0!

Рекурсивно:(DEFINE (FAC N) (IF (= N 1) 1 (* N (FAC (- N 1)))))

Итеративно: (DEFINE (FAC N) (DEFINE (F_ITER P I M) (IF (> I M) P (F_ITER (* P I) (+ I 1) M))) (F_ITER 1 1 N))

2.Да се напише функция, която пресмята xn, където n е цяло число.

<

>=

=

0 ,1

0 ,.

0 ,11

nакоx

nакоxx

nако

x

n

nn

Рекурсивно: (DEFINE (EXPON X N) (COND ((= N 0)1) ((> N 0) (* X (EXPON X (- N 1)))) (ELSE (/ 1 (EXPON X (- 0 N))))))

Итеративно:(DEFINE (EXPON N X) (DEFINE (EX_IT N S) (COND ((= N 0) S) ((> N 0) (EX_IT (- N 1)(* S X))) (ELSE (/ 1 (EX_IT (ABS N) S) )))) (EX_IT N 1)Y)

43

Page 44: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИЯ 6

НЯКОИ ДРУГИ ФУНКЦИИ В ЛИСП.Процедурни средства в езика. Аритметика в ЛИСП. Аритметични функции. Числени предикати. Програмиране на аритметични изрази. Логически функции.

1. Процедурни средства в езика

Езикът ЛИСП е функционален език, но за да се даде възможност някои елементи на програмата да се пишат в процедурен стил, има предвидени средства за предаване на управлението, завършване на изпълнението и организация на цикли.

1.1.Функцията LETВ глава 6 дефинирахме понятието локални променливи. Ще разгледаме

функцията LET, с която можем да дефинираме локални променливи, да определяме стойностите им и обсега на тяхната валидност. Освен това с помощта на тази функция може да изпълняваме последователности от изрази подобно на изразите на най-високо ниво.

Общият вид на функцията LET е следния:(LET ((<ЛОК-ПРОМ1> <ИЗРАЗ1>) ((<ЛОК-ПРОМ2> <ИЗРАЗ2>) - - - ((<ЛОК-ПРОМn> <ИЗРАЗn>) ) <ТЯЛО> )

При обръщението към функцията най-напред всяка ЛОК-ПРОМ получава оценката на съответния ИЗРАЗ. След това с така получените стойности се изпълняват изразите от тялото на функцията. Резултатът от обръщението е стойността на последния оценен израз от тялото. Ясно е, че ЛОК-ПРОМ са локални променливи и обсегът им на валидност е тялото на съответния LET. След завършване на функцията локалните променливи възстановяват предишните си стойности, ако са имали такива. Тъй като тялото на функцията е последователност от изрази, то влагането на обръщения е напълно възможно.

Тази функция подобрява яснотата на програмата и облекчава търсенето на грешки при тестване.(DEFINE X 5) (+ (LET ((X 2))(+ X (* X 10))) X)->27

Променливите се свързват с оценките едновременно. Това значи, че при свързване на поредната променлива не може да се ползват предходните променливи. (DEFINE X 2)(LET ((X 3) (Y (+ X 2))) (* X Y))->12Примери1.Нека са дадени списъците P -> (A B C) и Q -> (M H). Да разгледаме обръщението:(LET ( (R (APPEND P Q)) (G (APPEND Q P)) )

(CDR R )(CDR G ) ) -> (H A B C)

44

Page 45: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

2. По-долу е дефинирана функцията EXTRACT, при която S е точкова двойка и L е списък. Като използваме функцията LDIFF, дадена в задача № 24 от глава 6, се намира подсписък на L, започващ с първото появяване на единия елемент на [S] и завършващ с първото появяване на другия елемент на [S]. При неуспех резултатът е NIL.

(DEFINE (EXTRACT L S) (LET ((SUBLIST1 (MEMBER (CAR S) L)) (SUBLIST2 (MEMBER (CAR (CDR S)) L))) (COND ((MEMBER (CAR SUBLIST1 ) SUBLIST2) (APPEND (LDIFF SUBLIST2 SUBLIST1) (LIST (CAR SUBLIST1))) ) ((MEMBER (CAR SUBLIST2 ) SUBLIST1 ) (APPEND (LDIFF SUBLIST1 SUBLIST2) (LIST (CAR SUBLIST2)) ) ) (ELSE () ) ) ) ) 3.Следващото упражнение включва функцията SET, която е вградена в транслатора. Най-напред ще дадем кратко описание на тази функция. Функцията SET(няма я в DrScheme и PC Scheme ), е функция на два аргумента. Обръщението към нея изглежда по следния начин: (SET A B),където A и B са изрази, които се оценяват. Стойността на A трябва задължително да бъде атом. B може да има като стойност произволен S–израз. Стойността на обръщението към функцията SET е стойността на B, а като страничен ефект за стойност на стойността на A се присвоява стойността на B. Характерното тук е, че за разлика от функцията SETQ се оценяват и двата аргумента, като на стойността на първия се присвоява стойността на втория. Сега следва и самото упражнение – да се оценят изразите на най-високо ниво, ако те са част от програма на ЛИСП:

(SETQ A 'R)"(SETQ B 'P)" (SET A 'B) "A"B"R"

Решение:(SETQ A 'R)" -> R(SETQ B 'P)" -> P(SET A 'B)" -> PA" -> RB" -> PR" -> P

2.Аритметика в ЛИСПЧислата в ЛИСП, както и в другите езици за програмиране, са от цял или реален

тип. Те не се описват предварително. Записват се по следния начин:-цели числа – [±]цц…ц. Например, +12, 12 и т.н.;-реални числа – те могат да бъдат записвани по два начина:

45

Page 46: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

а) С десетична точка- [±]цц…ц.цц…ц. При такова записване реалните числа трябва да съдържат не повече от фиксиран от реализацията брой значещи цифри. Ако съдържат повече, те се отрязват като значещи нули в порядъка при вътрешното им представяне.Ето още няколко примера за реални числа:

+78.49, -12.1, 15.169.б) В експоненциално представяне с мантиса и порядък – то има следния вид: [±]цц…ц.цц…цЕ[±]цц. Мантисата се записва по същия начин, както и реалните числа с десетична точка, и отговаря на същите ограничения. Порядъкът съдържа най-много три цифри.Ето няколко примера на записване на реални числа:

+12.72Е-12, -0.19Е02, 98.71Е+02, 196Е-02, -2581Е3.Последното число е цяло по стойност, но е реално по вътрешна представяне (с плаваща точка) и с него не може да се работи като с цяло число.

Реалното число при записването си не трябва да започва или завършва с десетична точка, т.е. забранено е да се записва, например .5 или 5.. В този случай би трябвало да се запише: 0.5 или 5.0.

Знакът на числото трябва да се поставя непосредствено преди него. Вътре в числото не трябва да има интервали, тъй като те се третират като ограничители.

В различните версии на езика има разнообразни възможности за представяне на двоични и шестнайсетични числа, на комплексни числа, рационални числа, на числа с неограничена точност и т.н.

Забележки а) В ЛИСП числата се третират като специален вид атоми, чиито стойности (оценки) съвпадат с алгебричните стойности на числата.

Така например, ако в обръщението към функция е записано числото 5, то ще бъде оценено и за работа ще се вземе стойност +5, т.е. +5 ->+5, 5->+5, -5->-5; В ТОЗИ СЛУЧАЙ СТАВА ДУМА ЗА ЦЕЛИТЕ ЧИСЛА +5 И –5. Обаче –0.5Е01 ->-5 е реално число по своето вътрешно представяне.б) Функцията АТОМ? реагира на числата със стойност #T, т.е. числата се третират като атоми. Например: (АТОМ? 1) ->#T, (АТОМ? –21.915)-> #T. Ако е дадена променливата А със стойност реалното число –23.915, то(АТОМ? А) ->#Tв) Въпреки че числата се третират като атоми, понятията физическа и логическа еквивалентност съвпадат само за тези числа, чието представяне е от вида на указател, т.е. цяло число, което би могло да е адресна константа. Или:(EQ? 231 +231) -> #T(EQ? 987654321234 987654321234) ->Nil (() на PC Scheme;#f на Dr Scheme)(EQ? –2345 –2345) -> #T(EQ? 2.0 2) -> Nil (() на PC Scheme;#f на Dr Scheme)

3.Аритметични функцииАритметичните функции имат следния вид:

(<ИМЕ НА АРИТМЕТИЧНА ФУНКЦИЯ> А1 А2 … АN)Аi са аргументи на аритметичната функция, които в някои случаи могат да бъдат произволен брой. Те са изрази, които се оценяват, и стойностите им трябва да бъдат числа. Ако някоя от тях е реално число, то от това реално число нататък стойностите се разглеждат като реални и съответните аритметични действия – като върху реални числа, а резултатът ще е също реално число.

46

Page 47: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

2.1.Функция PLUS Това е функция на два или повече аргумента и изглежда по следния начин:(PLUS арг1 арг2 арг3) или(+ арг1 арг2 арг3)Функцията се прилага последователно отляво надясно върху алгебричните стойности на аргументите.На фиг.7.3 е даден един пример.

(+ 1 –0.1 2) -> 2.9

1 -0.1 2.0

2.9Фиг. 7.3

2.2.Функция TIMESФункцията умножава две или повече числа и има следния вид:

(TIMES арг1 арг2 арг3) или(* арг1 арг2 арг3)Например:(* (+ 2 3) (* 3 5)) -> 75(* (+ 1 2) –2 4) -> -24

2.3. Функция DIFFERENCEС тази функция се извършва последователно изваждане на числата. Обръщението е:

(DIFFERENCE арг1 арг2 арг3) или(- арг1 арг2 арг3)

Например:(- (* 4 5) (* 5 5) -3) -> -2(- 1 -1) -> 2

2.4. Функция QUOTIENTЗа деление на цели числа се използва функция, към която обръщението е:

(QUOTIENT арг1 арг2)Като резултат от последователното прилагане на функцията QUOTIENT отляво надясно върху стойностите на аргументите се получава тяхното частно. Ако се делят две цeли числа, при което се получава остатък, остатъка се пренебрегва. Например:(QUOTIENT 10 3)->3(QUOTIENT 20 7)->2(QUOTIENT 20 27)->0

2.5. Функция REMAINDERЗа деление на цели числа се използва функция, към която обръщението е:

(REMAINDER арг1 арг2)

47

Page 48: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Като резултат от последователното прилагане на функцията REMAINDER отляво надясно върху стойностите на аргументите се получава остатъка при целочислено деление.Например:(REMAINDER 10 3)-> 1(REMAINDER 20 6) ->2(REMAINDER 10 13) ->10

2.6. Функция /За деление на реални числа се използва функция, към която обръщението е:

(/ арг1 арг2 арг3)Ако се делят цели и реални числа, резултатът ще бъде както при делението на реални числа. При това в някои версии на езика се превключва на реална аритметика от момента на появяването на първия аргумент от тип реално число, например (/ 11 4 0.1) -> 20.0 понеже при целочислено делене 11 : 4 = 2, а след това 2 : 0.1 = 20.0, а в други версии (Dr Scheme и PC Scheme) е достатъчно който и аргумент да е от тип реален, за да се приложи реална аритметика върху всички аргументи, например (/ 11 4 0.1) -> 27.5 понеже делене 11 : 4 = 2.75 и 2.75 : 0.1 = 27.5. Но разбира се във всички версии (/ 11.0 4.0 0.1) -> 27.5.

2.7.Функция ABSABS е функция за намиране на абсолютна стойност на число. Обръщението към нея изглежда по следния начин:

(ABS арг)Например:(ABS (* 1 –5)) -> 5

2.8.Функция ADD1(няма я в Dr Scheme)Много често срещано действие при програмирането е добавянето или изваждането на единица. Следва обръщение към функцията, добавяща единица:(ADD1 арг) или (1+ арг)Например(1+ 4) -> 5(1+ -3) -> -2

2.9.Функция roundЗа да закръглим едно число от тип плаваща запетая до тип цяло, се използва следното обръщение:

(ROUND арг)Например:(ROUND 5.1)->5.0(ROUND 5.9) ->6.0(ROUND -5.1) ->-5.0(ROUND -5.5) ->-6.0

2.10. Функция TRUNCATE

(TRUNCATE арг)

48

Page 49: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

В резултат от изпълнението й се получава цялата част на аргумента, като дробната част се елиминира, т.е. не се закръгля. Например:(TRUNCATE -3.7) ->-3.0(TRUNCATE -3.2) ->-3.0(TRUNCATE 3.1) ->3.0(TRUNCATE 3.7) ->3.0

2.11. Функция FLOAT (няма я в DrScheme)За обратното преобразование – от цели числа в числа с плаваща точка се използва функцията FLOAT. Обръщението към нея е следното:

(FLOAT арг)Например:(FLOAT 1) -> 1.0

Функция MINUSПромяната на знака на едно число става със следното обръщение:(MINUS арг) или (- арг)Например: (- -6)->6

2.12. Функция EXPTЗа действието степенуване се използва следното обръщение:

(EXPT арг1 арг2),където арг1 и арг2 са изрази, които се оценяват и трябва задължително да имат числови стойности, В резултат от изпълнението на функцията се получава стойността на арг1, повдигната на степен стойността на арг2.Например:(EXPT 3 2) -> 9(EXPT 3.0 2) -> 9.0(EXPT 8 (/ 1 3) -> 2.0

2.13.Функция MAXMAX е функция за намиране на най-голяма стойност. Обръщението към нея е следното:

(MAX арг1 арг2 арг3)

Например:(MAX 2 4 3) -> 4(MAX 2 4 3 (/ 11 2) -6) -> 5

2.14. Функция MINMIN е функция за намиране на най-малката стойност. Обръщението към нея е следното:

(MIN арг1 арг2 арг3)Например:(MIN 2.1 4.2 1.3 5.0) -> 1.3

49

Page 50: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Числени предикатиТова са функции, чиито аргументи са числови, а стойностите им са #T и Nil (()

в PC Scheme или #f в DrScheme). Ще се спрем на някои от тях по-подробно.

2.15. Функция >Обръщението към тази функция е

(> арг1 арг2 арг3)Като резултат от прилагането й върху стойностите на аргументите се получава стойност #T, ако стойностите на аргументите са подредени в строго низходящ ред и Nil във всички останали случаи.Например:(> 7 5 4 2 1) -> #T(> 5 5) -> Nil(> 3.2 3.1 2 –2 –2.53 –4) ->#T

2.16.Функция <Обръщението към функция е

(< арг1 арг2 арг3)Обръщението към функцията има стойност #T, ако стойностите на аргументите са подредени в строго възходящ ред и Nil във всички останали случаи.Например:(< 5 6 9 20.7) -> #T(< 2 1) -> Nil

2.17. Функция =Тя е функция на два аргумента и обръщението към нея е:

(= арг1 арг2), където арг1 и арг2 са аритметични изрази, които се оценяват. В резултат от изпълнението на функцията = се получава стойност #T, ако алгебричните стойности на арг1 и арг2 са еднакви цели или реални числа, и стойност Nil във всички останали случаи. Забележка: В Dr Scheme броят на аргументите е неограничен.Следват няколко примера:(= 3 3 3) ->#T(= 3 3.0) ->#T(= 2.41 24.1E-01) ->#TФункцията EQ? е едно разширение на =. Поради това:(EQ? 'A 'A) -> #T, но(= 'A 'A) -> ERROR

2.18. Функция ZERO?Обръщението към нея е:

(ZERO? арг)Тя е предикат и дава стойност #T, ако стойността на арг е нула, и стойност Nil във всички останали случаи.

Функция NUMBER?Обръщението към нея е:

(NUMBER? арг)

50

Page 51: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Тя дава стойност #T, ако стойността на арг е число, и стойност Nil във всички останали случаи.

3. Програмиране на аритметични изразиПосредством вложения на описаните дотук функции е възможно да се построяват аритметични изрази в ЛИСП. Например изразът [A] – [V] : [C] може да се запише по следния начин: (- A (/ B C))

[B] [C]

A] [B] : [C]

[A] – [B] : [C]Но ако искаме да пресметнем ([A] – [V]) : [C], то ще трябва да запишем:(/ (- A B) C) -> ([A] – [V]) : [C]

Примери:

1.Да се преобразуват в Scheme изрази и да се оценят:0,5.(41-17/3)-19,5 2.(-4).6.(-8).10.(-12).14 (4/7+7/23)/(5/8-16/19)

2.Да се оценят следните изрази:(-(* 2 4)(/ 6 3))-> (DEFINE A 8)->(DEFINE B (- A 2))->

3.Да се дефинира функция ROUND, която за дадено число X получава най-близкото до X цяло число. За целта към X да се добави 0.5, умножено със знака на X, след което да се вземе цялата част на така полученото число.

4.Да се дефинира функция, която увеличава 2 пъти по-малкото от две числа.

5.Да се дефинира функция, която изчислява на стойността на функцията по дадено х:

>

≤<≤

=

1 ,

10 ,

0 x,0

)(4 xx

xxxf

6.Да се дефинира функция F по следния начин:

51

Page 52: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

−∞∈−∈

∈−+ ∞∈−

=

]0;(,

];0(,

]2;(,2

);2(,2

)(

xx

axx

aaxxa

axax

xf , където а>0

7.Да се намерят стойностите (без да се използва компютър) на по-долу дефинираната функция на Акерман при стойности на M 0, 1, 2 и 3 и на N - произволно цяло неотрицателно число.(DEFINE (AK M N) (COND ((ZERO? M) (+ N 1)) ((COND ((ZERO? N)(AK (- M 1) 1)) (ELSE (AK (- M 1)(AK M (- N 1))))))))

Отговор: N + 1, N + 2, 2N + 3 и 2N + 3 – 3

8.Да се дефинира функция, която по дадени реални коефициенти a, b и c решава уравнението: 02 =++ cbxax

9.Да се напише функция, която по зададено n пресмята сумата

)!12(

)1(....!5!3

sin12

n53

+−+−+−=

+

nxxx

xxn

.

10.Да се напише функция, проверяваща има ли цифра к в записа на числото n.

11.Да се напише функция, която пресмята по дадени x и n стойността на полиномаnxxx ++++ ...1 2 .

12.Да се напише функция, която намира сумата от цифрите на дадено число.

13.Да се напише функция, която намира сумата от четните числа в [a,b]

14.Да се напише функция, която намира сумата на числата от [а,b], чиято сума от цифрите =9.

15.Да се напише функция, която проверява има ли повтарящи се цифри в записа на число.

16.Да се напише функция, която обръща дадено число.

4. Логически функции

Логическите функции в ЛИСП се отнасят до основните логически действия, като отрицание, конюнкция, дизюнкция и др. В резултат на изпълнението им се получава стойност истина или лъжа. В ЛИСП лъжата се означава с NIL( () в PC Scheme и #f в DrScheme). Всяка друга стойност, различна от NIL, може да се разглежда като истина.

52

Page 53: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Така стойността на #T е един частен случай на истина, т.е. истина включва и стойността #T.

4.1. Функция AND - логическо “И” (конюнкция)Обръщението към тази функция изглежда по следния начин:

(AND арг1 арг2 арг3)В резултат на изпълнението й се получава стойност #T, ако стойностите на

всички аргументи са истина, т.е. различни от NIL, и стойност NIL, ако поне един от аргументите има стойност NIL.

Аргументите могат да бъдат произволни изрази. Те се оценяват отляво надясно, докато се стигне до аргумент, който има стойност NIL, или се изчерпят всички аргументи. След като е достигнат аргумент със стойност NIL, следващите аргументи не се оценяват.Например:(AND #T #T Nil (CAR Nil) (5 6))->() ;на PC Scheme(AND #T #T #f (CAR ()) (5 6))->#f ;на Dr Scheme

4.2. Функция OR - .логическо “ИЛИ” (дизюнкция)Обръщението към тази функция изглежда по следния начин:

(OR арг1 арг2 арг3)В резултат на изпълнението й се получава стойност #T, ако стойността на поне един аргумент е различна от NIL, и стойност NIL, ако всички аргументи имат стойност NIL.

Аргументите могат да бъдат произволни изрази. Те се оценяват отляво надясно, докато се стигне до аргумент, който има стойност различна от NIL. Останалите аргументи не се разглеждат.Например:(OR NIL #T NIL #T #T ) -> #T ;на PC Scheme(OR #f #T () #T #T)->#t ;на DrScheme

С помощта на логическите функции AND, OR и NULL (NOT) съгласно теоремата на Бул могат да се образуват произволни логически изрази. Възможни са много сложни вложения на тези функции, като при това трябва да се има предвид, че редът на записването им определя коя след коя функция ще се изпълни. Или това, че с най-висок приоритет е отрицанието, след това конюнкцията, а след нея – дизюнкцията не влияе на реда на изпълнението на функциите.

Примери:

1. Напишете функция EQLOG с два аргумента, която да дава стойност #T в случай, че двата аргумента са NIL или и двата са различни от NIL, в противен случай функцията да дава стойност NIL

Решение:(DEFINE (EQLOG L1 L2)(OR (AND L1 L2)(AND (NOT L1)(NOT L2)) ))

2. Напишете функцията EMPLY с два аргумента, която да дава стойност:-#T, ако първият елемент има стойност, различна от NIL, а вторият - NIL;- NIL в останалите случаи.

53

Page 54: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Решение:(DEFINE (EMPTLY L1 L2) (AND L1 (NOT L2)) )

3. Напишете функция XOR с два аргумента, която да дава стойност #T, ако единият аргумент е NIL, а другият е различен от NIL. В останалите случаи функцията на дава стойност NIL.

Решение:(DEFINE (XOR L1 L2) (OR (AND L1 (NOT L2))(AND (NOT L1) L2) ))

54

Page 55: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ЛЕКЦИЯ 7ФУНКЦИИ, ПРЕДИЗВИКВАЩИ ИЗПЪЛНЕНИЕ НА ДРУГИ ФУНКЦИИ.Функцията APPLY. Функционали. Функцията MAPCAR. Функцията за вход-изход. Други функции.

При разглеждането на функцията EVAL видяхме, че двойното изчисляване на аргумента дава възможност по време на изпълнението на програмата да се конструират различни изрази, които от своя страна да се изпълнят пак по време на същото изпълнение. Сега ще се спрем на по-сложни функции, предизвикващи изпълнението на други функции и с това даващи възможност за промяна на програмата или конструиране по време на изпълнение на някои части.

1. Функция APPLY.

Обръщението към тази функция изглежда по следния начин: (APPLY арг1 арг2)APPLY е функция на два аргумента. Аргументите са изрази, които се оценяват. Стойността на арг1 трябва да бъде атом, който е име на функция, дефинирана по-рано (чрез DEFUN или вградена). Стойността на арг2 трябва да е списък от фактически параметри на функцията. Те трябва да отговарят на описанието на съответната функция. В резултат от изпълнението на APPLY се формира обръщение към функцията с име стойността на арг1 и фактически параметри елементите на списъка, който е стойност на арг2, т.е. формира се обръщението

<([арг1] <АРГУМЕНТИ ОТ [арг2])>,след което се предизвиква изпълнение на това обръщение, като функцията се прилага върху аргументите, без да се оценяват повторно. (APPLY + '(1 2 3 4 5))->15.Изключение имаме само ако функцията, която се прилага е SETQ - тогава вторият аргумент (вторият елемент на списъка <АРГУМЕНТИ ОТ [арг2]) се изчислява преди прилагането на SETQ. Резултатът от изпълнението става оценка и на обръщението към APPLY.На фиг. 1 е даден един пример, в който A -> (5 7 9) и M -> +.(APPLY M A) -> 21

PLUS (5 7 9)

(PLUS 5 7 9)

21 Фиг. 1

Използването на функцията APPLY дава възможност за динамично формиране на обръщението към функция в определен момент от изпълнението, т.е. в зависимост от текущото състояние на процеса на изчисленията може да се извърши обръщение към една или друга функция с едни или други входни аргументи. По такъв начин може да се осигури тъй нареченото “управление на програмата от данните” – едно изключително мощно средство при решаване на задачи от областта на изкуствения интелект.

На фиг.2 са дадени два примера, като стойността на A е CAR, а на B е ((X)).

55

Page 56: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

X

(APPLY ‘SETQ (LIST ‘X ‘(CAR Y)))->Z, при Y-> (Z)

X (CAR Y) оценяване на SETQ (X (CAR Y)) аргументите формиране (SETQ X (CAR Y)) на обръщение

(Z) изпълнение

Z на обръщението Z (APPLY A B) -> X

CAR ((X))

CAR ‘(X))

(X)

Фиг.2 Следователно функцията APPLY обединява чрез CONS името и аргументите,

след което се предизвиква изпълнението на така формираното обръщение, като се смята, че пред аргументите има QUOTE (т.е., че те вече са оценени).

2. ФункционалиФункционали ще наричаме този вид функции, които прилагат дадена функция

върху различни аргументи. Може да се мисли, че прилагането на функцията към различните данни става едновременно и поради това тези функции се наричат агрегатни. Те се различават както по броя и вида на аргументите си, така и по това, как обработват резултатите, получени от прилагането на функцията. Съвсем накратко ще кажем за различните възможности:

-едноаргументна, двуаргументна и пр. функция, която се прилага над аргументите;

-резултатите се обединяват физически в списък; последователно се извеждат; функцията или стойност NIL или #T в зависимост от резултатите на отделните изпълнения и пр.;

-функцията се прилага към всеки елемент от аргумента списък; или към целия списък, след това към CDR на списъка и т.н. до достигане на празния списък.

56

Page 57: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

3. Функция MAPCAR(няма я в DrScheme).

Това е функция (функционал) на два аргумента. Обръщението към нея е следното:(MAPCAR арг1 арг2),където арг1 и арг2 са изрази, които се оценяват. арг1 трябва да има за стойност символен атом, който представлява име на функция с един аргумент. Стойността на арг2 е списък от аргументи (B1 B2 … BN) за функцията с име арг1. MAPCAR прилага функцията с име арг1 върху всеки от аргументите Bi, без предварително оценяване и получените резултати обединява в същия ред в списък. При наличието на многопроцесорна система е възможно да се извършат паралелно пресмятанията на всички стойности на функцията с име арг1.Забележка: Предполага се, че елементите на <арг2> са предварително оценени и <арг1> се прилага директно върху тях.

На фиг. 3 с помощта на пример е показано действието на тази функция.(MAPCAR ‘MAX ‘((3 3 5 4)(6 5 5 4)(3 2 3 3))->(5 6 3)

MAX ((3 3 5 4)(6 5 5 4)(3 2 3 3))

(3 3 5 4) (6 5 5 4) (3 2 3 3)

(5 6 3) Фиг. 3

Упражнения

1.Нека L има стойност списък. Да се определи броя на елементите му.Решение:Един начин за решение е даден в задача 12 на глава 6.Ето още един начин:(DEFINE (F X) 1)(DEFINE (LENGTH L) (APPLY + (MAPCAR F L)) )

2.Нека стойността на L е списък от числа и вектори. Да се заместят векторите със сумите от елементите им.Например, ако е даден списъка (2 (3 4 6)(1 1) 5), да се получи списъка (2 13 2 5).

3.Нека L има стойност атом или списък. Да се намери броят на атомите.

4.Нека L има стойност списък. Да се намери най-голямата дълбочина на вложение.

57

Page 58: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

4. Работа с р-списъциФункцията PUTPROP. Функцията GETPROP. Функцията REMPROP. Асоциативни списъци. Функцията ASSOC.

Често се налага някакъв обект да се характеризира със списък от различни свойства. Свойствата се задават с техните имена, а всяко свойство може да има различни стойности. Например една ваза може да има свойство цвят, а това свойство може да има различни стойности – жълт, зелен, син и т.н. Някои свойства могат да имат числени стойности, например свойството тегло може да има стойност 200 г, 1 кг и т.н. За да бъде възможно задаването на атом, означаващ обект, към който да се приписват атоми, означаващи свойства, е необходимо да се разшири понятието атом. От една страна (както досега), атомът се характеризира със своето име и стойност. От друга страна обаче, той се характеризира със свойства и техните стойности, обединени в списък. Този списък се нарича Р-списък (от PROPERTIES- свойства). Всяко свойство се представя посредством атом с име – името на свойството, наречено още индикатор, и стойност – стойността на индикатора, наречена още значение.

Едно по-прегледно представяне на горното определение е дадено на фиг. 4.

Фиг. 4.

Номерата на индикаторите не определят реда на подреждане– това не е масив! Индикаторите се записват по реда на тяхното въвеждане. Те се търсят в Р-списъка посредством техните имена, а не по номер. Името на атома и индикаторите са символни атоми. Стойността на атома и значенията могат да бъдат произволни S-изрази, т.е. точкови двойки, списъци, атоми и т.н.

Атомът получава стойност чрез функцията SETQ и тази стойност се извлича чрез механизма на оценяване. Чрез двойката функции PUTPROP и GETPROP се добавят нови свойства (индикатор значение) и се търсят значенията на вече съществуващи свойства. С помощта на функцията REMPROP може да се премахне определен индикатор с неговото значение.

4.1.Функция PUTPROP(няма я в DrScheme) PUTPROP е функция на три аргумента. Обръщението към нея изглежда по следния начин:

(PUTPROP арг1 арг2 арг3),където арг1, арг2 и арг3 са изрази, които се оценяват. арг1 има стойност атом, който представлява име на атом. арг2 има стойност произволен S–израз, който става по-късно значение на индикатор с име [арг3]. арг3 има стойност символен атом, който представлява име на индикатор. Резултатът от изпълнението на функцията PUTPROP е показан на фиг. 5.

58

Име на атом

индикатор

индикатор

л

индикатор

Ст. на атом

значениезначение значение

Page 59: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(PUTPROP A1 A2 A3)-> 1. Ако в Р-списъка на атома с име [A1] има индикатор с име [A3], присвоява му се значение [A2], като старото значение се губи.

2. Ако в Р-списъка на атома с име [A1] няма индикатор с име [A3], в Р-списъка се създава индикатор с име [A3] и значение [A2].

3. И в двата случая стойността на обръщението става [A2].

Фиг. 5Или накратко стойността на обръщението е [арг2], като имаме и странични

ефекти, посочени в т.1 или т. 2. Например(PUTPROP 'A ' (1 2) 'ИНД3) -> (1 2)

В резултат на изпълнението на функцията се създава индикатор с име ИНД3 и значение (1 2), или на вече създадения индикатор ИНД3 се присвоява ново значение – (1 2).

4.2.Функция getprop(няма я в DrScheme)Това е функция на два аргумента, като обръщението към нея е следното:

(GETPROP арг1 арг2),където арг1 и арг2 са изрази, които се оценяват. арг1 и арг2 имат стойности символни атоми. За атома [арг1] в Р-списъка се търси индикатор с име [арг2] и неговото значение става стойност на обръщението към getprop, а ако такъв индикатор не съществува в Р-списъка на атома [арг1], получава се стойност NIL (виж фиг.6.).

(GET A1 A2)-> 1. Значението на индикатора с име [A1]. 2. NIL, ако в Р-списъка на [A1] няма индикатор с име [A2].

Фиг.6Нека А и ИНД3 са атоми, чиито стойности са определени по-горе чрез

PUTPROP. Тогава(GETPROP 'A 'ИНД3) -> (1 2)(GETPROP 'A 'СУМА) -> NIL

Функция REMPROP(няма я в DrScheme)

Тя е функция на два аргумента и обръщението към нея изглежда по следния начин:

(REMPROP арг1 арг2),където арг1 и арг2 са изрази, които се оценяват и имат стойности символни атоми. В резултат на изпълнението на функцията от Р-списъка на атома [арг1] се премахва индикатора с име [арг2] заедно с неговото значение и стойността на обръщението става #T. Ако няма индикатор с такова име, стойността на обръщението става NIL. Например(PUTPROP 'K 50 'KOD)->50(GETPROP 'K 'KOD)->50(REMPROP 'K 'KOD)->(K)(GETPROP 'K 'KOD)->()PUTPROP, GETPROP, REMPROP са основните функции за работа с Р-списъци. Важно е да се отбележи, че индикаторите и техните значения са независими от стойността на атома присвоена му чрез SETQ.

59

Page 60: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Сега ще разгледаме как Р-списъците могат да се използват за представяне на свойствата на обектите. Нека разгледаме структурата на фиг.7.

Фиг.7.Тази структура се получава по следния начин:(SET! купа '(световна европейска републиканска градска))->(световна европейска републиканска градска)(PUTPROP 'купа '(жълт кафяв червен син) 'цвят)-> (жълт кафяв червен син)(PUTPROP 'купа '(метал стъкло дърво глина) 'материал)->(метал стъкло дърво глина)(PUTPROP 'купа '(футбол баскет хокей тенис) 'спорт)->(футбол баскет хокей тенис)и представлява знанието ни за спортните купи, като описва възможните значения на различните индикатори. Тогава, ако имаме конкретно описание на спечелена градска купа по тенис от глина и с кафяв цвят от някой спортен клуб – например от БЪРЗОНОГИТЕ-ПИНГВИНИ – то би изглеждало по следния начин:

получено посредством:(SET! купа-на-БП 'градска) -> градска(PUTPROP купа-на-БП 'кафяв 'цвят) -> кафяв(PUTPROP купа-на-БП 'глина 'материал) -> глина(PUTPROP купа-на-БП 'тенис 'спорт) -> тенис,с проста програмка бихме могли да проверим верността на описанието на тази купа. Например, ако купата на клуба бе въведена по следния начин:(SET! купа-на-БП 'световна) -> световна(PUTPROP купа-на-БП 'кафяв 'цвят) -> кафяв(PUTPROP купа-на-БП 'тиква 'материал) -> тиква(PUTPROP купа-на-БП 'тенис 'спорт) -> тенис,то нашата програма би разпознала, че такава купа няма.Ето още един пример:(DEFINE CUP 'EUROPE)->CUP(PUTPROP CUP 'GOLD 'COLOR)->GOLD(PUTPROP 'EUROPE 'METAL 'MATERIAL)->METAL(PUTPROP CUP 2.7 'TEGLO)->2.7(GETPROP 'EUROPE 'COLOR)->GOLD(GETPROP CUP 'COLOR)->GOLD(GETPROP CUP 'TEGLO)->2.7(GETPROP CUP 'MATERIAL)->METAL

60

Купа спорт

(световна европейска

републиканска градска...)

Купа на БП

спорт материал

цвят

градска тенис глина кафяв

материал цвят

(футбол баскет хокей

тенис...)

(метал стъкло дърво

глина...)

(жълт кафявчервенсин...)

Купа спорт

(световна европейска

републиканска градска...)

Page 61: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(REMPROP CUP 'MATERIAL)->(EUROPE TEGLO 2.7 COLOR GOLD)(GETPROP CUP 'MATERIAL)->( )Обърнете внимание, че в GETPROP, PUTPROP, REMPROP няма значение дали ползвате името или стойността на атома.

5. Асоциативни списъци

Асоциативен списък е списък от вида((<A1> . <E1>) … (<AN> . <EN>)),

където Ai са атоми, а Ei са произволни S-изрази, например:((A . B)(C . (C D E))) ≡ ((A . B)(C C D E))Такъв списък може да се създаде така: (LIST (CONS 'A 'W)(CONS 'B 2)(CONS 5 'A3))

5.1.Функция ASSOC(няма я в DrScheme)Функцията е предназначена да работи с асоциативни списъци. Тя е функция на

два аргумента и обръщението към нея изглежда по следния начин:(ASSOC арг1 арг2),

където арг1 и арг2 са изрази, които се оценяват. Стойността на арг1 трябва да е атом, а на арг2 - асоциативен списък. В резултат от изпълнението на функцията ASSOC се получава точкова двойка (<Ai> . <Ei>) (тя принадлежи на асоциативния списък), където i е номерът на първата (отляво надясно) точкова двойка, за която [арг1] е Ai и стойност NIL в противен случай.Например нека са дадениS -> ((A . X)(B . (3 4))(M .N))P -> BQ -> NR -> (A B C)Тогава действието на функцията се илюстрира на фиг.8. с няколко примера(ASSOC P S) -> (B . (3 4))

B ((A . X)(B . (3 4))(M . N))

(B . (3 4))(ASSOC 'M S) -> (M . N)(ASSOC Q S) -> NIL

N ((A . X)(B . (3 4))(M . N))

NIL(ASSOC(CAR R) S) -> (A . X)

(A B C) A ((A . X)(B . (3 4))(M . N))

(A . X) Фиг. 8.

61

Page 62: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Упражнения

1.Нека LF има стойност от следния вид:((<АТОМ> . <ИМЕ НА ФУНКЦИЯ>) … (<АТОМ> . <ИМЕ НА ФУНКЦИЯ>))Нека функциите, чиито имена са посочени в този списък, нямат аргументи. Нека освен това F има стойност атом. Да се изпълни функцията с име – името на функцията от точковата двойка [LF], за която [F] съвпада с <АТОМ> и за стойност на израза да се даде получената оценка. Ако не се намери такава функция, да се даде стойност NIL.Решение:(DEFINE (W F FL) (LET ((R (ASSOC F FL))) (AND R (EVAL (LIST (CDR R))))))Забележка: Функцията LET присвоява на локални променливи текущи стойности – в случая на R резултата от обръщението към (ASSOC F FL).(DEFINE (A2) (* 2 2))(DEFINE (A3) (* 2 2 2))(DEFINE (B) (+ (A2) (A3)))(DEFINE LP (LIST (CONS 1 B) (CONS 2 A2)(CONS 5 A3)))(W 2 LP)->4

2.Да се дефинират функции REMASSOC и PUTASSOC за работа с асоциативни списъци по следния начин: REMASSOC да има два аргумента и обръщението към нея да е (REMASSOC A1 A2), където A1 и A2 да са изрази, които се оценяват. Стойността на A1 трябва да е атом, а на A2 - асоциативен списък. В резултат на изпълнението да се получава асоциативен списък [A2], в който първото срещане (ако има такова) на точкова двойка с първи елемент [A1] е премахнато, например:(REMASSOC ‘B ‘((A . X)(B . Y)(C . Z) )) ->((A . X) (C . Z))

PUTASSOC да има два аргумента и обръщението към нея да е (PUTASSOC A1 A2), където A1 и A2 да са изрази, които се оценяват. Стойността на A1 трябва да е точкова двойка с първи елемент атом, а на A2 - асоциативен списък. В резултат на изпълнението да се получава асоциативният списък [A2], в който първото срещане (ако има такова) на точковата двойка с първи елемент първия елемент на [A1] да е премахнато и към него (асоциативния списък) в началото да е добавена точковата двойка [A1], например:(PUTASSOC '(B . Y) '((A . X) (C . Z)) ) ->((B . Y)(A . X) (C . Z))(PUTASSOC '(B . Y) '((A . X) (B . D) (C . Z)) ) -> ((B . Y)(A . X)(C . Z))

Така дефинираните функции REMASSOC и PUTASSOC са в известен смисъл аналогични на функциите REMPROP и PUTPROP, но са за работа с асоциативни списъци, а не с Р-списъци. Същата аналогия се забелязва между функциите ASSOC и GETPROP.Решение:(DEFINE (REMASSOC A1 A2)

62

Page 63: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(COND ((NULL? A2) ()) ((EQ? A1 (CAAR A2)) (CDR A2 ) ) (ELSE (CONS (CAR A2) (REMASSOC A1 (CDR A2)) ) ) ))(DEFINE (PUTASSOC A1 A2) (CONS A1 (REMASSOC (CAR A1) A2)) )

6. Функция за вход-изход. Функцията READ. Функцията PRINT. Други функции.

6.1. Фукция READИзпълнението на функцията READ предизвиква прекъсване на работата на

интерпретатора до момента, в който потребителят не въведе от клавиатурата произволен S–израз. След това интерпретаторът продължава своята работа, като най-напред завършва изпълнението на функцията READ, чието обръщение дава като стойност въведения израз, без той да бъде оценяван. Функцията няма аргументи и обръщението към нея има следния вид:

(READ)Примери1.(COND ((EQ? (READ) 'A) #T) ((EQ? (READ) 'B) NIL))AРезултатът от горния израз ще се появи на екрана или ще се отпечата след прочитане на атома A и той ще бъде #T, понеже функцията READ е прочела атом с име A.2.(COND ((EQ? (READ) 'A) #T ) ((EQ? (READ) 'B) (SET! L (READ))))PB(L I S T)Резултатът от горния израз ще излезе на екрана след последователното прочитане на атомите P и B и списъкът (L I S T) и той ще бъде:(L I S T)

6.2. Функция PRINT(няма я в DrScheme)Функцията PRINT има един аргумент, чиято стойност може да е произволен S–

израз. Действието на функцията е следното: аргументът се оценява и неговата стойност се извежда на екрана, в началото на нов ред. Стойността на обръщението към функцията е NIL.

Обръщението към функцията е следното:(PRINT арг.).

Пример(PRINT (SET! L '(L I S T)))В резултат на екрана ще излезе следното:( L I S T)

6.3.Други функции

Функция PRINC(няма я в DrScheme)Функцията PRINC има един аргумент, чиято стойност може да е произволен S–

израз. Действието на функцията е същото като на PRINT, без преминаване на нов ред. Стойността на обръщението към функцията е NIL.

Обръщението към функцията е следното:

63

Page 64: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

(PRINC арг.).

Пример (DEFINE (PROBA) (PRINC ‘N=) (PRINC (* 7 5)))Ако се обърнем към функцията с(PROBA)В резултат на екрана ще излезе следното:N=35

Функция DISPLAY Функцията DISPLAY има един аргумент, чиято стойност може да е произволен

S–израз. Действието на функцията е следното: аргументът се оценява и неговата стойност се извежда на екрана.

Обръщението към функцията е следното:(DISPLAY арг.).

За разлика от PRINT не се преминава на нов ред.

Примери(DISPLAY "СУМАТА Е ")(DISPLAY (+ 5 4))-> СУМАТА Е 9DISPLAY може да се използва за организиране на интерфейса.(DEFINE (PROBA2) (DISPLAY 'ВЪВЕДИ_N=) (REV (READ))) ; задача 17 от глава 7

Функция NEWLINE Функцията NEWLINE предизвиква преминаване на нов ред. Функцията няма

аргументи и обръщението към нея има следния вид:(NEWLINE)

Стойността на обръщението към функцията е NIL.

Упражнения

1.Да се напише функция, която създава списък по дадена дължина.

2.Да се напише функция, която отпечатва числата в [a,b].

3.Имаме 3 пилона и n диска с различен диаметър поставени на един от тях. Преместването на дисковете може да става по един и не може да се постави диск с по-голям диаметър върху диск с по-малък. Да се напише функция, която отпечатва преместванията на дисковете от един пилон на друг с помощта на третия.

4.Да се напише функция, която разлага число на прости множители.

11.Прилагане на езика ЛИСП за търсене по образецСписъчно представяне на факт и образец. Функцията MATCH за сравняване на факта с образеца.

64

Page 65: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Списъчно представяне на факт и образец

Видяхме, че списъците могат да се използват за представяне на различни информационни структури. Например:(ябълка цвят зелен)(ябълка цвят червен)(блок_а поддържа блок_б блок_с)(блок_е поддържа блок_д блок_т блок_р)представят различни факти.

Очевидно е, че първите два списъка имат нещо общо, може да твърдим, че те са сходни, понеже се отнасят за плода ябълка и неговия цвят. Така че, би било добре да ги класифицираме по някакъв начин в една група. Също така се вижда, че третият и четвъртият списък също имат някакво сходство – може би в областта на строителството и сигурността на някакви конструкции. Или те образуват друга група. Но между двете групи, колкото и голяма фантазия да имаме трудно ще намерим някакво сходство, освен, разбира се, че са списъци.

Сега да помислим по какъв начин можем да съставим два образеца, които да подхождат съответно към първата и втората група факти. Най-напред ще направим уговорката, че със знака “?” ще заместваме произволен елемент в списък, а със знака “*” – един или повече последователни елемента от списък. Тогава за двете групи от факти ще имаме следните два образеца, представени чрез списъци:(ябълка цвят ?)(? поддържа *)

За простота на примерите, ще работим само със списъци от атоми, но по принцип разсъжденията ни ще са валидни и при списъци от произволни изрази, т.е. имащи и подсписъци на произволно ниво.

С помощта на примерните образци можем да разпознаем дали даден факт се отнася за цвета на ябълките или за многоетажно подредени блокове. Можем да съставим и редица други образци, които да са свързани с проблемната област, за която ще е предназначена програмната ни реализация.

И така, фактите представяме като списъци от атоми, а образците като списъци от атоми и някои специални символи

Дотук можем да определяме сходство между факти и образци. Но в редица случаи е необходимо да се извлича и разликата между фактите, сходни с един и същ образец. Това може де стане, като въведем още два специални символа за описване на образец:>АТОМ – АТОМ е произволен атом, а >АТОМ предизвиква съпоставяне с един атом от факта, както при ?, но освен това като стойност на АТОМ се присвоява съответния атом от факта.*АТОМ – АТОМ е също произволен атом, а *АТОМ предизвиква съпоставяне с един или повече последователни атома от факта, както при *, но освен това предизвиква присвояване на АТОМ като стойност списък на съответните атоми от факта.Сега, ако сравним факта:(блок_а поддържа блок_б блок_с)с образеца(>ОПОРА поддържа *ПРЕДМЕТИ)

65

Page 66: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

ще получим от една страна успешно съпоставяне, а от друга страна, на ОПОРА ще се присвои стойност блок_а, а на ПРЕДМЕТИ – списъкът (блок_б блок_с).

Функцията MATCH за сравняване на факта с образецаНека с P да означим образеца, а с D – факта. Функцията, която ще извършва

съпоставянето между образец и факт, по начина определен в предния параграф ще се нарича MATCH.

Първоначално ще дефинираме две помощни функции ATOMCAR и ATOMCDR, които дават съответно първия знак на атома и атома без първия знак:(DEFINE ATOMCAR (A)(CAR (UNPACK A)) )(DEFINE ATOMCDR(A)(PACK (CDR (UNPACK A))) )

В тези дефиниции използваме две вградени функции: PACK и UNPACK (няма ги в DrScheme и PC Scheme ).

Общият вид на функцията PACK е следния:(PACK <арг.>),където <арг.> е израз, който се оценява. Неговата оценка трябва да бъде списък от атоми. В резултат от изпълнението на функцията се получава атом съставен от имената на атомите в първоначалния списък, т.е. ако стойността на А е (<а1><а2>...<аn>), то оценка на обръщението (PACK А) ще бъде атома<а1><а2>...<аn>.

Общият вид на функцията UNPACK е следния:(UNPACK <арг.>),където <арг.> е израз, който се оценява. Неговата оценка трябва да бъде атом от букви. В резултат от изпълнението на функцията се получава списък съставен от буквите в първоначалния атом, т.е. ако стойността на А е <б1><б2>...<бn>, то оценка на обръщението (UNPACK А) ще бъде списъка (<б1> <б2>...<бn>).

А ето и дефиницията на MATCH:(DEFINE MATCH (P D) (COND ((AND (NULL? P) (NULL? D))T) ((OR (NULL? P) (NULL? D)) NIL) ((OR (EQUAL (CAR P) '?) (EQUAL (CAR P)(CAR D))) (MATCH (CDR P)(CDR D) )) ((EQUAL (CAR P) '*) (COND ((MATCH (CDR P)(CDR D)) T) ((MATCH P (CDR D)) T)) ) ((AND (ATOM? (CAR P)) (EQUAL (ATOMCAR (CAR P)) '>) (MATCH (CDR P)(CDR D)) ) (SET (ATOMCDR (CAR P)) (CAR D) )T) ((AND (ATOM? (CAR P)) (EQUAL (ATOMCAR (CAR P)) '*) ) (COND ((MATCH (CDR P)(CDR D)) (SET (ATOMCDR (CAR P))(LIST (CAR D))) T) ((MATCH P (CDR D)) (SET (ATOMCAR (CAR P)) (CONS (CAR D) (EVAL (ATOMCDR (CAR P))))) T) ) ) ) )Забележка: В програмата се използва функцията SET разгледана в глава 7 зад.3.

66

Page 67: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

Първоначално се прави проверка за край – дали P и D са празни списъци и ако това е така, стойността на функцията става Т. Ако не, проверява се дали един от двата списъка не е празен. Това може да се случи, ако при съпоставянето елементите от единия списък са изчерпани, а в другия не – случай в който стойността на функцията трябва да е NIL. Ако и това крайно условие не е изпълнено проверяваме дали първият елемент на образеца Р не е “?” (проверка за първия специален символ, заместващ един елемент) или дали са еднакви първите елементите на факта и образеца. При вярно условие функцията се прилага рекурсивно към факта и образеца без първите им елементи. Ако не е вярно, проверява се дали първият елемент на Р е “*” (проверка за втория специален символ, заместващ един или повече елемента). При успех функцията се прилага рекурсивно към факта и образеца без първите елементи и ако това съпоставяне завърши с успех, стойността на функцията става Т. Ако не, съпоставя се образеца Р с факта D без първия му елемент и ако съпоставянето е успешно, стойността на функцията стана Т.

Следват проверки за третия специален символ – “>…”, т.е. случая”>ATOM”, и за четвъртия специален символ – “*…”, т.е. случая “*ATOM”, които са подобни на горните два случая, но се извършват и присвоявания на стойности.

Важно е да се отбележи, че навсякъде съпоставянията се извършват чрез рекурсивни обръщения към функцията MATCH. Ако например са дадени образеца (*A B) и факта (C E B), атомът A играе роля на глобална променлива – в долните нива на рекурсията тя получава стойност, която се запазва и в по-горните нива. Освен това съществено е, че присвояванията на стойност става едва след като е завършило успешно съпоставянето на максималната дълбочина.

Възможностите на функцията MATCH могат да се разширят и със следния специален символ:<ATOM - където ATOM е произволен атом. В този случай се извършва съпоставяне между факта и стойността на ATOM.Специалните символи ? и >ATOM могат да се включат и в една друга конструкция: ?(RESTRICT <предикат1> <предикат2> … <предикатN>), >ATOMкъдето <предикатi> представлява име на дефиниран едноаргументен предикат (имащ стойност T или NIL). Конструкцията RESTRICT осигурява съпоставянето със специалните символи ? и >ATOM, само ако съответният елемент от факта удовлетворява всички предикати, посочени в конструкцията RESTRICT. По този начин могат да се задават допълнителни условия за извършването на съпоставянето по образец и присвояването на нови стойности.Примери1. (MATCH '(PLUS >A1 >A2) '(PLUS 5 6) ) -> T и стойността на А1 става 5, а на А2 – 6.2. (MATCH '(>A) '(P)) -> T и стойността на А става Р.(MATCH '(>A) '(P)) -> T(MATCH '(>A) '(A)) -> NIL, защото стойността на А вече е Р, което не е еквивалентно с А.3. Нека да дефинираме отличен успех по следния начин:(DEFINE ОТЛИЧЕН (N) (COND ((> N 5.49) T)))и да имаме списък от студенти с техния успех от вида:

67

Page 68: ЛЕКЦИИ - iitb.weebly.comiitb.weebly.com/uploads/3/3/4/5/3345556/referati_org-ezik-za-funkc... · Основи н функционалното програмиране. ... работа

L -> (ПЕНЧО успех 3.25 ИВАН успех 5.49 МЕРИ успех 5.50 ГАНЬО успех 4.99 ХАРИ успех 5.55 …)Тогава:(MATCH '(* >отличник успех (RESTRICT ? ОТЛИЧЕН) *) L) -> Tи стойността на отличник ще е МЕРИ, а при:(MATCH '(* >отличник успех (RESTRICT >успех ОТЛИЧЕН) *) L) -> T и стойността на отличник пак ще е МЕРИ, а на успех – 5.5.

68