Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Функциональное программирование

..pdf
Скачиваний:
0
Добавлен:
12.11.2023
Размер:
14.84 Mб
Скачать

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

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

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

Фактически термин «функциональное программирование» используется при объединении в систему методов решения классов задач, обладающих исследовательскими аспектами, что влечет за собой необходимость развития полученных решений. Система предполагает общую логику уточнения решаемых задач и формализацию обобщенных решений на основе специально выбранных базовых конструкций.

Во всей полноте идеи функционального программирования поддержаны в проекте Lisp 1.5, выполненном Дж. Маккарти и его коллегами. В этом исключительно мощном языке не только реализованы основные средства, обеспечившие практичность

131

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

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

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

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

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

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

132

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

Напомним, что «Лисп» появился в 1958 г. как язык для обработки списков. Получил достаточно широкое распространение в системах искусственного интеллекта. Имеет несколько потомков: Planner (1967), Scheme (1975), Common Lisp (1984).

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

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

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

Из языков с энергичной семантикой упомянем ML и два его современных диалекта – Standard ML (SML) и CaML. Последний имеет объектно-ориентированного потомка – Objective CaML (O’CaML).

Среди языков с ленивой семантикой наиболее распространены два – Haskell и его более простой диалект Clean.

Функциональные языки еще долго не смогут вытеснить императивные, но все-таки за функциональными языками будущее.

133

Сомнительно, что чисто функциональные языки наберут обороты. А вот функциональные «фишки» в императивных языках программирования уже сейчас приобретают нужную базу.

Функциональные языки, использующиеся в системах искусственного интеллекта:

Языки искусственного интеллекта на основе «Лиспа»: o PLANNER,

o QLISP, o KRL, o FRL.

Языки экспериментальных систем и их оболочек:

o AnaList (ведение боя) «FranzLisp – военное дело»,

o PROSPECTOR (поиск месторождений) «InterLisp-

геология»,

o REACTOR (диагностика атомных реакторов) «Lisp-ин- женерия»,

o CODES (определение концептуальной модели баз данных) «USI Lisp-информатика»,

o IDT (ремонт ЭВМ PDP-11) «FranzLisp – компьютерные системы»,

o LES (заправка челночного космического корабля жидким кислородом в центре Кеннеди) «Zeta_Lisp-космос»,

o MACSYMA (символьные преобразования в алгебре) «Lisp-математика»,

o MYSIN (набор антимикробной терапии) «Lisp-медицина», o DENDRAL (вывод молекулярной структуры неизвест-

ных соединений) «InterLisp-химия»,

o EVRISCO (обучение эвристикам, в том числе проекти-

рование СБИС) «INTERLISP».

Языки систем искусственного интеллекта: o PERSONAL CONSULTANT (Lisp),

o KEE (система инженерии знаний),

o PICON (интеллектуальное управление производственным процессом на лисп-машине LAMBDA).

134

РЕШЕНИЕ ЗАДАЧ И УПРАЖНЕНИЙ

Упражнение для самоконтроля 1 к теме 1

Задача 1.1

А) (* 3.234 (+ 45.6 2.43))

Б) (+ 55 21.3 (* 1.54 2.5432) – 32)

В) (/ (+ 34 – 21.5676 – 43) (+ 342 (* 32 4.1)))

Задача 1.2

А) > (car (cdr (cdr (cdr (list 1 2 3 ‘а 4))))) или (CADDDR (list 1 2 3 ‘а 4))

Б) > (cdr (cdr (cdr (cdr (list 1 2 3 4 ‘a))))) или (CDDDDR (list 1 2 3 4 ‘a))

В) > (cdr (cdr (list (list 1) (list 2 3) (car (list 'a 4))))) или (CDDR (list (list 1) (list 2 3) (car (list 'a 4))))

Г)>(car(car(cdr(list(list1)(list(cdr(cdr(list23'a)))(list4)))))) или (CAADR (list (list 1) (list (CDDR (list 2 3 'a)) (list 4)))) Д) > (cdr (list (list 1) (car (cdr (cdr (list 2 3 ‘a 4))))))

или (cdr (list (list 1) (CADDR (list 2 3 ‘a 4))))

Е) > (cdr (list 1 (cdr (list 2 (cdr (cdr (list 3 4 (cdr (list 5 (cdr (list 6 ‘a)))))))))))

не вычисляет.

(print (cdr (list 1 (cdr (list 2 (cdr (cdr (list 3 4 (cdr (list 5 (cdr (list 6 'a)))))))))))))

(((((A)))))

или

(cdr (list 1 (cdr (list 2 (CDDR (list 3 4 (cdr (list 5 (cdr (list 6 ‘a))))))))))

(((((A)))))

135

Задача 1.3

А) (+ 2 (* 3 5))

Б) ошибка, так как ‘(* 3 5) является символьным выраже-

нием (* 3 5)

В) ошибка неправильно используется оператор ‘(quote) (+ 2 (’ * 3 5))

Г) 17

Д) (QUOTE QUOTE) Е) 6

Задача 1.4

А) NIL

Б) T

В) T

Задача 1.5

(print (car (cdr (list 'первый 'второй 'третий 'четвертый))))

ВТОРОЙ

Задача 1.6

(defun AND4 (x1 x2 x3 x4) (and (and x1 x2) (and x3 x4)))

или

(defun AND4 (x1 x2 x3 x4) (and x1 x2 x3 x4)) (defun OR4 (x1 x2 x3 x4) (or (or x1 x2) (or x3 x4)))

Тест:

>(and 4 t t t t) T

Задача 1.7

(defun nillt (L) (cond ((not (atom L)) T)))

Тест:

>(nillt 'a) NIL

>(nillt (list 'a 'b 'c)) T

136

Задача 1.8

(defun factorial (n) (do

((result 1)) ((= n 1) result)

(setq result (* result n)) (setq n (– n 1))

))

Тест:

>(factorial 3) 6

Задача 1.9

(defuncarlist(L)

(cond((atom(carL));если1-йэлементатом

(carL));товывод1-йэлемент

((cond((atom(CADRL)) ;иначеесли2-йэлементатом

(CADRL)) ;товывод2-йэлемент

((cond((and(=(length(CDDRL)) 1)(atom(CADDRL))) ;иначеесли1-йэлемент3-го спискаатомидлина3-госписка=1

(CADDRL)) ;товывод1-йэлемент3-госписка.

(L);иначевыводсписка

))

))

)

)

Тест:

>(carlist (list 'a 'b 'c)) A

>(carlist (list (list 'a 'aa) 'b 'c)) B

>(carlist (list (list 'a 'aa) (list 'b ‘bb) 'c)) C

>(carlist (list (list 'a 'aa) (list 'b 'bb) (list 'c 'cc))) ((A AA) ('B 'BB) ('C 'CC))

137

Упражнение для самоконтроля 2 к теме 1

Задача 1.10

(set 'x1 (list 'IVANOV 1980 4 'АНАТОЛИЙ 'НИНА)) (set 'x2 (list 'PETROV 1980 3 'ИВАН 'АННА))

(set 'x3 (list 'IVANIN 1982 3 'АНАТОЛИЙ 'НИНА)) (set 'x4 (list 'SEMENOV 1981 4 'ИВАН 'МАРИЯ)) (set 'xx1 0)

(set 'xx2 0) (set 'xx3 0) (set 'xx4 0)

(defun rovest (name1 name2)

(cond ((eql name1 (car x1)) (set 'xx1 (CADR x1))) ((eql name1 (car x2)) (set 'xx1 (CADR x2))) ((eql name1 (car x3)) (set 'xx1 (CADR x3))) ((eql name1 (car x4)) (set 'xx1 (CADR x4)))

)

(cond ((eql name2 (car x1)) (set 'xx2 (CADR x1))) ((eql name2 (car x2)) (set 'xx2 (CADR x2))) ((eql name2 (car x3)) (set 'xx2 (CADR x3))) ((eql name2 (car x4)) (set 'xx2 (CADR x4)))

)

(cond ((= xx1 xx2) (print 'ровесники))

((< xx1 xx2) (print (list name1 'младше name2))) ((> xx1 xx2) (print (list name1 'старше name2)))

)

)

(defun sr_ball (name1 name2)

(cond ((eql name1 (car x1)) (set 'xx1 (CADDR x1))) ((eql name1 (car x2)) (set 'xx1 (CADDR x2))) ((eql name1 (car x3)) (set 'xx1 (CADDR x3))) ((eql name1 (car x4)) (set 'xx1 (CADDR x4)))

)

(cond ((eql name2 (car x1)) (set 'xx2 (CADDR x1)))

138

((eql name2 (car x2)) (set 'xx2 (CADDR x2))) ((eql name2 (car x3)) (set 'xx2 (CADDR x3))) ((eql name2 (car x4)) (set 'xx2 (CADDR x4)))

)

(cond ((= xx1 xx2) (print (list 'у name1 name2 'баллы_

одинаковые)))

((< xx1 xx2) (print (list 'у name1 'средний_балл_меньше_ чем_у name2)))

((> xx1 xx2) (print (list 'у name1 'средний_балл_больше_ чем_у name2)))

)

)

(defun rodstv (name1 name2) (cond ((eql name1 (car x1)) (set 'xx1 (CADDDR x1)) (set 'xx2 (CDDDDR x1)))

((eql name1 (car x2)) (set 'xx1 (CADDDR x2)) (set 'xx2 (CDDDDR x2)))

((eql name1 (car x3)) (set 'xx1 (CADDDR x3)) (set 'xx2 (CDDDDR x3)))

((eql name1 (car x4)) (set 'xx1 (CADDDR x4)) (set 'xx2 (CDDDDR x4)))

)

(cond ((eql name2 (car x1)) (set 'xx3 (CADDDR x1)) (set 'xx4 (CDDDDR x1))

)

((eql name2 (car x2)) (set 'xx3 (CADDDR x2)) (set 'xx4 (CDDDDR x2)))

((eql name2 (car x3)) (set 'xx3 (CADDDR x3)) (set 'xx4 (CDDDDR x3)))

((eql name2 (car x4)) (set 'xx3 (CADDDR x4)) (set 'xx4 (CDDDDR x4)))

)

139

(cond ((and (EQL xx1 xx3) (EQL xx2 xx4)) (print (list name1 name2 'родственники))) ((print (list name1 name2 ' =

не_родственники)))))

Тест:

>(rovest 'IVANOV 'IVANIN) (IVANOV СТАРШЕ IVANIN) (IVANOV СТАРШЕ IVANIN) >(sr_ball 'IVANOV 'IVANIN)

(У IVANOV СРЕДНИЙ_БАЛЛ_БОЛЬШЕ_ЧЕМ_У IVANIN) (У IVANOV СРЕДНИЙ_БАЛЛ_БОЛЬШЕ_ЧЕМ_У IVANIN) >(rodstv 'IVANOV 'SEMENOV)

(IVANOV SEMENOV = НЕ_РОДСТВЕННИКИ)

(IVANOV SEMENOV = НЕ_РОДСТВЕННИКИ)

Задача 1.11

(set 'x1 (list 'IVANOV 1980 4 'АНАТОЛИЙ 'НИНА 1)) (set 'x2 (list 'PETROV 1980 3 'ИВАН 'АННА 1))

(set 'x3 (list 'IVANIN 1982 3 'АНАТОЛИЙ 'НИНА 1)) (set 'x4 (list 'SEMENOV 1981 4 'ИВАН 'МАРИЯ 1)) (set 'xx1 0)

(set 'xx2 0) (set 'xx3 0) (set 'xx4 0)

(defun rovest (name1 name2) (if (eql name1 (car x1))

(set 'xx1 (CADR x1)) (if (eql name1 (car x2)) (set 'xx1 (CADR x2)) (if (eql name1 (car x3))

(set 'xx1 (CADR x3)) (set 'xx1 (CADR x4))

)))

(if (eql name2 (car x1)) (set 'xx2 (CADR x1))

140