ГОСУДАРСТВЕННЫЙ КОМИТЕТ РОССИЙСКОЙ ФЕДЕРАЦИИ ПО ВЫСШЕМУ ОБРАЗОВАНИЮ ----------------------

advertisement
ГОСУДАРСТВЕННЫЙ КОМИТЕТ РОССИЙСКОЙ ФЕДЕРАЦИИ
ПО ВЫСШЕМУ ОБРАЗОВАНИЮ
---------------------МОСКОВСКИЙ ЭНЕРГЕТИЧЕСКИЙ ИНСТИТУТ
-----------------------------------------------------
Утверждено
учебным управлением МЭИ
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
по курсу
Языки и методы программирования
СБОРНИК ЗАДАНИЙ ПО ПРОГРАММИРОВАНИЮ
НА ЯЗЫКАХ ЛИСП, ФРЛ И ПРОЛОГ
Москва
.
Издательство МЭИ
1997
-2-
УДК
621.398
М 545
УДК: 681.3.06(072)
Сборник заданий по программированию на языках ЛИСП,
ФРЛ и ПРОЛОГ. Байдун В.В., Чернов П.Л. / Под ред. Чернова
П.Л. - М.: Изд-во МЭИ, 1996 - 40 с.
В методических указаниях приводятся задания по программированию на языках ЛИСП, ФРЛ и ПРОЛОГ. Рассматриваются вопросы методики написания программ на этих языках
"искуственного интеллекта", применяемых при построении
баз знаний на основе сетевых и логических моделей представления знаний. Приводятся пояснительные примеры.
Указания предназначены для слушателей ФПКП и студентов специальности "Прикладная математика", выполняющих
практические задания и типовой расчет с применением персональных ЭВМ, а также для аспирантов, занимающихся
практическими вопросами разработки и реализации систем,
ориентированных на знания.
─────────────────────
С Московский энергетический институт, 1997 г.
.
-3-
ВВЕДЕНИЕ
Проблема представления и обработки знаний является ключевой
для области искусственного интеллекта. От ее успешного решения непосредственно зависят эффективность и "интеллектуальность" прикладных программных систем.
В рамках второй части курса "Языки и методы программирования"
рассматриваются и изучаются инструментальные средства разработки
интеллектуальных систем, основанных на сетевых и логических моделях
представления знаний. Практическое освоение языков программирования
ЛИСП ( LISP - LISt Processing ), ФРЛ ( FRL - Frame Representation
Language ) и ПРОЛОГ ( PROLOG - PROgramming in LOGic ) выполняется
на практических и лабораторных занятиях, а также самостоятельно при
выполнении курсовой работы.
.
-4-
1. ЗАДАНИЯ ДЛЯ ПРАКТИЧЕСКИХ ЗАНЯТИЙ
На практических занятиях студенты осваивают методы программирования задач, в том числе и однотипных, на различных языках программирования. В каждом разделе приводится пример написания программы, иллюстрирующий особенности решения задач данного класса.
1.1. Задания по языку программирования ЛИСП
Язык программирования ЛИСП является функциональным языком, одной из главных особенностей которого является ориентация на рекурсивные вычисления. Программа на языке ЛИСП представляет собой как
правило определение ряда относительно небольших по объему функционально законченных функций, из которых как из кирпичиков может быть
собрана большая программная система, удовлетворяющая требованиям
конкретного пользователя.
При разработке программ на ЛИСП может быть рекомендована методика написания рекурсивных функций, изложенная ниже.
1. Определение необходимых входных параметров и выбор параметра(ов), по которому(ым) будет проводиться рекурсия. Выходное значение функции может быть только одно, и оно всегда возвращается как
результат вычисления этой функции.
2. В рамках функции COND или IF последовательно рассматривать
вырожденные (тривиальные) случаи в порядке возрастания их общности
и формировать результат функции для каждого такого случая.
3. Для более общих случаев также в порядке возрастания их общности формировать рекурсивные вызовы, редуцируя при этом параметр(ы), по которым проводится рекурсия, к уже рассмотренным их вырожденным случаям.
При определении рекурсивных функций рекомендуется особое внимание обращать на необходимость остановки рекурсии, так как некорректное задание ее условий может привести к бесконечному циклическому процессу.
1.1.1. Рекурсивная обработка числовой информации
Данный класс задач содержит множество вычислительных задач по
формулам, связанным, например, с различными рекурентными соотноше-
-5-
ниями. Рассмотрим, как может быть реализована на ЛИСП функция вычисления факториала, задаваемая следующим соотношением:
0! = 1
1! = 1 * 0!
2! = 2 * 1 = 2 * 1!
3! = 3 * 2 * 1 = 3 * 2!
.....................
N! = N * (N - 1) * (N - 2) * ... * 1 = N * (N - 1)!
Количество входных параметров для этой функции равно 1 и задает значения того числа N, факториал которого необходимо посчитать.
В случае некорректного задания исходного числа ( N < 0 ) результат
функции должен быть равен 0. Тривиальная ситуация, завершающая рекурсию, определяется значением N = 0. Все другие возможные ситуации
при N > 0 определяются одним и тем же рекурсивным соотношением.
Объединяя все возможные ситуации с помощью условной функции СОND
имеем следующее определение функции FACT:
( DEFUN FACT ( LAMBDA ( N )
(COND (( MINUSP N ) 0 )
(( = 0 N ) 1 )
( T ( * N ( FACT ( - N 1 ))))) ))
1. Подсчитать сумму квадратов целых чисел в заданном интервале
значений от M до N включительно.
2. Определить наименьшее общее кратное двух заданных чисел.
3. Определить наибольший общий делитель двух заданных чисел.
4. Вычислить квадратный корень из заданного числа.
5. Первые два члена ряда Фибоначчи равны 1 и 2. Каждый следующий член ряда равен сумме двух предыдущих. Определить функцию, вычисляющую N-ый член ряда Фибоначчи.
1.1.2. Рекурсивная обработка списковой информации
Данный класс задач содержит множество задач обработки сложноструктурированной информации, представленной в виде списков произвольной структуры. Рекурсивная обработка при этом как правило
строится по принципу обработки первого элемента списка и продолжению рекурсии с остатком списка без первого элемента ( "рекурсия
вширь" ). Если текущий первый элемент представляет собой в свою
-6-
очередь список, то для его обработки может быть также применен
принцип рекурсии ( "рекурсия вглубь" ). Как правило, при работе со
списками тривиальным случаем, используемым для остановки рекурсии,
считается случай достижения списком-параметром состояния "пустой
список".
Рассмотрим, как может быть реализована на ЛИСП функция вычисления количества подсписков на всех уровнях исходного списка.
Количество входных параметров для этой функции равно 1 и задает значение входного списка L, в котором необходимо посчитать количество подсписков. Тривиальная ситуация, завершающая рекурсию, определяется значением L = NIL, при этом количество подсписков для
такого L равно 0. Все другие возможные ситуации означают, что в
списке L есть как минимум один элемент. Если текущий первый элемент
не является подсписком, то результат будет определяться количеством
подсписков в остатке списка. Если же этот элемент - подсписок, то
результат будет равен сумме количества подсписков в остатке списка,
количества подсписков в самом этом текущем элементе плюс 1 за этот
текущий элемент-подсписок. Объединяя все возможные ситуации с помощью условной функции СОND имеем следующее определение функции
SUBLIST_AMOUNT, использующей как рекурсию вширь, так и вглубь.
( DEFUN SUBLIST_AMOUNT ( LAMBDA ( L )
(COND (( NULL L ) 0 )
(( LISTP (CAR L)) ( + 1
(SUBLIST_AMOUNT (CAR L))
(SUBLIST_AMOUNT (CDR L))
) )
( T (SUBLIST_AMOUNT (CDR L))) ) ) )
6. Определить предикат, распознающий списки, имеющие четное
(нечетное) количество элементов.
7. Подсчитать сумму всех числовых атомов в списке произвольной
структуры.
8. Определить максимальную глубину списка произвольной структуры.
9. Найти максимальный элемент в числовом списке произвольной
структуры.
10. Написать функцию, выполняющую вычисление арифметических
выражений, заданных в виде списка. Используемые операции - умножить
-7-
(*), разделить (/), сложить (+), вычесть (-). При вычислении учитывать приоритет операций и скобочные выражения.
Пример-пояснение: (eval-expr '(4 + (-2 + 4) * 3)) => 10
1.1.3. Конструирующая рекурсия
Данный класс задач содержит множество задач обработки информации, представленной в виде списков, в том числе и произвольной
структуры, и формирования на их основе в качестве результата других
списков. Рекурсивная обработка при этом как правило не отличается
от методов, описанных в двух предыдущих параграфах. Основное отличие заключается в том, что на обратном шаге рекурсии при формировании результата используются функции-конструкторы CONS, APPEND,
LIST.
Рассмотрим, как может быть реализована на ЛИСП функция, удаляющая из списка произвольной структуры все атомы, кроме положительных чисел.
Формирование алгоритма для этой задачи аналогично представленному в 1.1.2. При формировании результата на обратном шаге рекурсии
будем использовать функцию CONS для включения в результат либо положительных чисел, либо подсписков, которые могут также содержать
положительные числа. Все другие элементы будут на этом шаге пропускаться. Необходимо помнить, что использование конструктора CONS
сохраняет в результирующем списке порядок элементов исходного списка.
( DEFUN LIST_POSITIVE_NUMBER ( LAMBDA ( L )
(COND ((NULL L) NIL )
((LISTP (CAR L))
(CONS (LIST_POSITIVE_NUMBER (CAR L))
(LIST_POSITIVE_NUMBER (CDR L)) ) )
((PLUSP (CAR L))
(CONS (CAR L) (LIST_POSITIVE_NUMBER (CDR L))))
( T (LIST_POSITIVE_NUMBER (CDR L)) ) ) ) )
11. Сформировать список простых множителей заданного числа.
12. Реверсировать элементы списка произвольной структуры на
всех уровнях.
Пример-пояснение: исходный список - (A (B C) D (E (F G)))
результирующий список - (((G F) E) D (C B) A)
-8-
13. Линеаризовать список произвольной структуры.
Пример-пояснение: исходный список - (A (B C) D (E (F G)))
результирующий список - (A B C D E F G)
14. Сформировать список, являющийся пересечением двух заданных
линейных списков. Повторяющиеся в исходных списках элементы должны
входить в результирующий список не более одного раза.
15. Сформировать список чисел ряда Фибоначчи (см. задание N 5)
от первого числа до числа с заданным номером включительно.
1.1.4. Последовательные, циклические и итерационные вычисления
Рекурсия не всегда является удобной для решения некоторых задач, по своей природе последовательных или циклических. Большая
размерность задачи тоже может быть препятствием для эффективного
решения ее рекурсивным методом из-за того, что требуется дополнительная память на каждом шаге рекурсии для запоминания всех параметров. В таких случаях в ЛИСП используются специальные функции
PROG и LOOP соответственно для последовательных и циклических вычислений, которые позволяют писать программы практически в стандартной операторной форме.
Особенности, которые надо иметь в виду при использовании LOOP,
заключаются как в необходимости самостоятельно отслеживать изменение параметра цикла ( списка ), так и в необходимости самостоятельного формирования результата. Для этой цели часто используют дополнительный формальный параметр, не указываемый при вызове функции.
Это требует корректного задания его начального значения до входа в
функцию LOOP. Кроме того, необходимо помнить о том, что неявный
COND в теле LOOP может быть условием завершения цикла, поэтому все
проверки в теле цикла необходимо выполнять с помощью явного COND.
Рассмотрим, как может быть реализована на ЛИСП с использованием механизма LOOP функция, удаляющая из списка произвольной структуры все атомы, кроме положительных чисел. Сравните ее с рекурсивным определением в предыдущем параграфе.
( DEFUN LIST_POSITIVE_NUMBER_LOOP ( LAMBDA ( L R )
( SETQ R NIL)
( LOOP
((NULL L) R )
(COND ((LISTP (CAR L))
-9-
(PUSH (LIST_POSITIVE_NUMBER_LOOP (CAR L)) R ))
((PLUSP (CAR L))
(PUSH (CAR L) R )) )
(POP L ) ) ) )
16. Посчитать с заданной точностью сумму бесконечного ряда,
каждый член которого задается формулой: k
X / k ! , где k изменяется
от 1 до бесконечности, а значение Х задано.
17. Найти последний элемент линейного списка.
18. Реализовать с помощью LOOP задание N 12 из 1.1.3.
19. Удалить из числового линейного списка все элементы, не
входящие в заданный интервал значений.
20. Задан список символьных атомов. Заменить во всех атомах
заданный символ на другой заданный символ, но не более чем заданное
число раз вхождений в каждом атоме.
1.1.5. Функционалы
Данный класс задач содержит множество задач однотипной обработки информации, содержащих в качестве входного параметра имя другой функции, использующейся в процессе вычисления.
Рассмотрим, как может быть реализована на ЛИСП функция, проверяющая, какие элементы исходного списка удовлетворяют заданному условию F, с использованием функционала FUNCALL.
( DEFUN CONTROL_LIST (LAMBDA ( L F )
(COND ((NULL L) NIL )
((FUNCALL F (CAR L)) (CONS T (CONTROL_LIST (CDR L) F)))
( T (CONS NIL (CONTROL_LIST (CDR L) F)))) ))
Примеры-пояснения:
(CONTROL_LIST '(5 -7 12 -3 -77) 'MINUSP) => (NIL T NIL T T)
(CONTROL_LIST '(5 -7 12 -3 -77) 'PLUSP) => (T NIL T NIL NIL)
Реализация той же самой функции с помощью MAP-функционалов будет выглядеть следующим образом (необходимо помнить, что количество
списков при вызове MAP-функции должно равняться арности функции F):
- 10 -
( DEFUN CONTROL_LIST_MAP (LAMBDA ( L F )
( MAPCAR F L) ))
21. Сформировать список, содержащий номера позиций элементов
исходного списка, удовлетворяющих заданному условию.
22. Задан линейный числовой список. Сформировать список сумм
подмножеств элементов исходного списка таким образом, что на первом
месте должна стоять сумма всех элементов списка, на втором - сумма
элементов без первого, на третьем - сумма элементов без первых двух
и т.д.
23. Удалить из исходного линейного списка все вхождения заданного элемента.
24. Оставить в исходном линейном списке не более одного вхождения каждого элемента.
25. Даны два исходных списка одинакового размера. Сформировать
из неравных друг другу элементов с одинаковыми порядковыми номерами
точечные пары, объединив их в один результирующий список.
1.1.6. Ассоциативные списки и списки свойств
26. Извлечь из ассоциативного списка элементы, ключи которых
удовлетворяют заданным условиям.
27. Исходный список содержит имена объектов, списки свойств
которых содержат некоторую информацию. Определить для каждого объекта количество пар <ключ-значение>.
28. Исходный список содержит имена объектов, списки свойств
которых содержат некоторую информацию. Другой список содержит некоторое количество ( больше 1 ) флагов. Сформировать список объектов,
содержащих не менее двух флагов из заданного списка.
29. Пусть в списке свойств атома может быть специальное свойство с ключом ISA, значение которого является именем другого списка
свойств, называемого списком-прототипом, из которого могут наследоваться недостающие свойства. Написать функцию (GET-ISA <имя списка
свойств> <имя свойства> ), которая в случае отсутствия искомого
свойства в исходном списке выдает значение первого найденного такого же свойства среди всех ISA-прототипов данного списка свойств.
30. На складе имеется несколько видов продукции. Ассортимент
каждого вида продукции представлен также несколькими наименованиями. Задать информацию о имеющихся на складе товарах и их количестве
- 11 -
с помощью списков свойств. Определить функции, позволяющие получать
информацию о наличии некоторого товара на складе и корректирующие
информацию о наличии при завозе и вывозе заданного количества товара.
1.2. Задания по языку программирования ФРЛ
1.2.1. Создание фреймов и извлечение информации из них
Фрейм представляет собой многоуровневый ассоциативный список,
позволяющий описывать различные объекты и связи между ними. При
этом каждый слот отражает значение некоторого свойства заданного
объекта. Это значение может быть или явным ( аспект $VALUE ), или
заданным по умолчанию ( аспект $DEFAULT ). Кроме того, значение может быть представлено или в декларативной ( описательной ) форме,
или в процедуральной ( комментарий STATUS: со значением EVAL ) форме, применение которой позволяет вычислять значение свойства каждый
раз при необходимости его использования. Ниже приводится пример
создания фрейма и пополнения его дополнительной информацией.
( DEFRAMEQ FRAME_1_2_1
(SLOT_1 ($VALUE (EX1))
($DEFAULT (EX2)) )
(SLOT_2 ($VALUE (PROC1 (STATUS: EVAL)
(PARM: :FRAME :SLOT))))
)
( FPRINT '(FRAME_1_2_1))
-----------------------------( FRAME_1_2_1
( SLOT_1 2 3($VALUE (EX1))
($DEFAULT (EX2))
)
( SLOT_2 ($VALUE (PROC1 2 ( 3STATUS: EVAL)
(PARM: 2 3:FRAME 2 3:SLOT)))
)
)
- 12 -
-----------------------------( FASSERTQ FRAME_1_2_1
(SLOT_3 ($DEFAULT (EX3)))
(SLOT_1 ($ALUE (EX1) 3 2(EX4)))
(SLOT_2 ($VALUE (EX5)))
)
( FPRINT '(FRAME_1_2_1))
-----------------------------( FRAME_1_2_1
(SLOT_3 ($DEFAULT (EX3))
)
( SLOT_1 2 3($VALUE (EX4) (EX1))
($DEFAULT (EX2))
)
( SLOT_2 ($VALUE (EX5)
(PROC1 2 ( 3STATUS: EVAL)
(PARM: 2 3:FRAME 2 3:SLOT)))
)
)
-----------------------------31. Создать фреймы, описывающие фрагмент библиотечной системы
( содержащие как декларативную, так и процедуральную ( в том числе
использующую переменные ФРЛ-среды ) составляющие ).
32. Добавить во фреймы, определенные в предыдущем задании, дополнительную информацию всеми имеющимися способами.
33. Извлечь из определенных в предыдущих заданиях фреймов информацию по заданному множеству запросов.
34. Реализовать функцию последовательного просмотра на экране
фреймов из заданного списка. Предусмотреть запрос о направлении
дальнейшего просмотра списка фреймов.
35. Имеются фреймы, описывающие фрагмент системы по обмену
квартир. Реальзовать функцию поиска информации о квартирах, удовлетворяющих заданному критерию.
1.2.2. Присоединенные процедуры
При работе с фреймами кроме выполнения явно указанных пользователем операций могут автоматически выполняться также и другие,
- 13 -
скрытые от пользователя, операции обработки при возникновении определенных ситуаций. Такие ситуации определяются заранее, и при их
возникновении запускаются присоединенные процедуры, связанные с
конкретной ситуацией. Эти своеобразные "демоны" могут выполнять любую дополнительную обработку данных, в том числе и тех, которые не
входят во фрейм, содержащий описание присоединенной процедуры. Ниже
приводится пример задания присоединенных процедур, автоматически
запускаемых при удалении, добавлении или извлечении данных из фрейма. Необходимо заметить, что действие данных присоединенных процедур распространяется только на те слоты, в которых они определены,
и не распространяется на другие слоты фрейма. Кроме того, в ФРЛ существуют два типа функций, по разному относящихся к присоединенным
процедурам. Одни из них активизируют присоединенные процедуры, а
другие этого не делают. Эти ситуации особо оговариваются при определении встроенных функций ФРЛ.
( DEFRAMEQ FRAME_1_2_2
(SLOT_1 ($VALUE (EX1))
($IF-ADDED ((SIGNAL 'ДОБАВЛЯЕТСЯ)))
($IF-REMOVED ((SIGNAL 'УДАЛЯЕТСЯ))) )
(SLOT_2 ($VALUE (EX2))
($IF-GETED ((SIGNAL 'ИЗВЛЕКАЕТСЯ))) )
)
( PASSERTQ SIGNAL (X)
(PRINT (LIST X " ДАННОЕ " :VALUE " ИЗ ФРЕЙМА " :FRAME
" СЛОТА " :SLOT )) )
( FPUT FRAME_1_2_2 SLOT_1 3 2 $VALUE 'EX3)
( ДОБАВЛЯЕТСЯ ДАННОЕ EX3 ИЗ ФРЕЙМА FRAME_1_2_2
СЛОТА SLOT_1)
EX3
( FPUT FRAME_1_2_2 SLOT_2 3 2 $VALUE 'EX4)
EX4
( FDELETE FRAME_1_2_2 SLOT_1 $VALUE 'EX3)
EX3
- 14 -
( FREMOVE FRAME_1_2_2 SLOT_1 $VALUE 'EX1)
( УДАЛЯЕТСЯ ДАННОЕ EX1 ИЗ ФРЕЙМА FRAME_1_2_2
СЛОТА SLOT_1)
EX1
36. Обеспечить автоматический подсчет частоты обращения к заданному фрейму с сигнализацией о каждом кратном 10 обращении.
37. Вместимость вагона 40 т. Товарный состав содержит 6 вагонов. Каждый вагон и состав описывается своим фреймом. Кроме того,
есть еще один фрейм, содержащий информацию о количестве и наименовании сформированных и отправленных составов. Реализовать функцию,
моделирующую загрузку вагона определенным количеством груза. При
превышении вместимости вагона груз размещается в следующем вагоне,
при формировании состава информация о нем включается в главный
фрейм и происходит переход к формированию следующего состава. Реализовать указанный алгоритм с помощью $IF-ADDED на всех уровнях.
38. Ситуация та же, что и в предыдущем задании, только на
станции прибытия требуется отгрузить заданное количество груза.
Корректировку информации о наличии груза, вагонов и составов реализовать с помощью $IF-REMOVED.
39. Обеспечить автоматический контроль корректности информации
о наличии на станции прибытия (см. предыдущее задание) количества
составов, не превышающих количество имеющихся путей.
40. Во фрейме имеется слот с закодированным значением информации. Обеспечить ее извлечение по паролю ( с использованием
$IF-NEEDED ).
1.2.3. Организация сетей фреймов
Каждый фрейм может представлять собой полностью определенную
закрытую единицу информации, задающую один конкретный объект. Однако такой подход при проектировании и разработке баз знаний не может
быть признан удовлетворительным из-за того, что это может привести
к дублированию большого количества информации, сложностей с поддержкой ее обновления и как следствие, к получению противоречивой
информации. Эта проблема решается эффективно в том случае, если
конкретная инфомация ( например, о текущем количестве студентов в
МЭИ ) содержится лишь в одном месте, а все другие объекты, которым
эта информация необходима, просто ссылаются на нее. Такой принцип
- 15 -
построения базы знаний называется наследованием свойств, и в ФРЛ он
реализуется с помощью механизма АКО-иерархии, при котором фреймы
связаны друг с другом в сеть, и поиск необходимой информации, отсутствующей в данном фрейме, осуществляется системой автоматически
во всех других фреймах, доступных по АКО-иерархии. Ниже приведен
пример фрагмента сети фреймов АКО-иерархии и показаны примеры поиска информации в ней.
( DEFRAMEQ FRAME_1_2_3_1
(SLOT_1 ($VALUE (EX1)))
(SLOT_2 ($VALUE (EX2)))
(INSTANCE ($VALUE (FRAME_1_2_3_2) (FRAME_1_2_3_3)))
)
( DEFRAMEQ FRAME_1_2_3_2
(SLOT_3 ($VALUE (EX3)))
(SLOT_2 ($VALUE (EX4)))
(AKO ($VALUE (FRAME_1_2_3_1)))
)
( FGET FRAME_1_2_3_2 SLOT_2)
(EX4 EX2)
( FGET1 FRAME_1_2_3_2 SLOT_2)
(EX4)
( FGET1 FRAME_1_2_3_2 SLOT_1)
(EX1)
( FGET FRAME_1_2_3_2 SLOT_4)
NIL
( FGET FRAME_1_2_3_2 SLOT_2 '(C))
((EX4 (IN: FRAME_1_2_3_2)) (EX2 (IN: FRAME_1_2_3_1)))
41. С помощью косвенного наследования задать часть информации
во фрагменте библиотечной системы (см. задание 31).
42. Задать информацию о фрагменте библиотечной системы с помощью AKO-иерархии.
43. Имеется система фреймов, организованная в циклическую
- 16 (круговую) структуру. Обеспечить проход по циклу заданное количество раз в любую сторону, начиная с любого фрейма.
44. Сформировать сетевую структуру фреймов с необходимыми процедурами, описывающую ситуацию на складе (см. задание 30) и обеспечивающую корректировку информации при завозе/вывозе продукции. Предусмотреть, что склад имеет ограниченный фиксированный объем.
45. Исходный список содержит информацию о студентах факультета. Сформировать AKO-иерархию факультета, предусмотрев автоматическую генерацию фреймов, описывающих конкретного студента, на основе
фрейма-прототипа, с заданием дополнительной информации о нем ( имя,
возраст и т.д. ) в диалоговом режиме.
Пример-пояснение: вид исходного списка - (АВТФ
(А-1-95 (ИВАНОВ ПЕТРОВ .... ))
(А-2-95 (СИДОРОВ ФРОЛОВ .... ))
...............
(А-14-90 (ЕГОРОВ ПОПОВ .... )) )
1.3. Задания по языку программирования ПРОЛОГ
Язык программирования ПРОЛОГ является языком логического программирования, активно используемым в исследованиях по искусственному интеллекту. Одной из главных особенностей языка является его
непроцедурная ориентация. Программа на языке ПРОЛОГ представляет
собой множество фактов, описывающих предметную область, и правил,
отражающих взаимодействие объектов в этой предметной области ( в
том числе возможны и рекурсивные определения правил ). Поиск информации, удовлетворяющей заданному запросу, интерпретатор системы выполняет автоматически, используя встроенные механизмы сопоставления
объектов и возврат в случае неуспеха.
При разработке программ на ПРОЛОГ может быть рекомендована
следующая методика, изложенная ниже.
I. Анализ предметной области.
1. Определение необходимых типов и структур данных.
2. Определение множества исходных фактов.
3. Определение множества необходимых правил.
II. Реализация правил
1. Определение для каждого правила необходимых входных и
выходных параметров (связанных или свободных при вызове правила) и
- 17 выбор параметра(ов), по которому(ым) будет проводиться рекурсия
( если она требуется ).
2. Определение для каждого правила множества вырожденных
(тривиальных) случаев в порядке возрастания их общности, приводящих
к истинности данного правила, и задание их в виде правил без правой
части.
3. Для более общих случаев также в порядке возрастания их
общности формировать правые части правил, содержащие обращения к
другим правилам ( в том числе, возможно, и к самим себе), редуцируя
при этом входные параметры к уже рассмотренным их вырожденным случаям. Не забывать при этом обязательно означивать выходные (свободные) переменные, определенные в левой части правила.
4. Множество всех определений правила с одним именем называется процедурой, которая может быть истиной на заданом наборе
входных параметров. В этом случае выходные параметры сопоставляются
с данными, обеспечившими истинность данного предиката.
1.3.1. Рекурсивная обработка числовой информации
Рассмотрим на примере вычисления факториала основные моменты,
возникающие при обработке целочисленной информации.
Дополнительные типы данных, как правило, в этих задачах определять не требуется, достаточно использования стандартных доменов.
Для завершения рекурсии используются факты, исходными данными для
которых являются значения входных переменных, равные 0 или реже 1.
Для факториала при входном параметре N = 0 результат по определению равен 1, что задается фактом в первой строке секции
clauses. Все другие случаи при N > 0 определяются рекурсивным правилом во второй строке. При некорректном задании входного параметра
( N < 0 ) ни факт, ни правило в секции clauses не сопоставляются с
исходной целью, поэтому ответом на запрос в этом случае будет сформированное системой сообщение " No solution ".
predicates
fact(integer,integer)
clauses
fact(0,1).
fact(N,F):- N > 0, N1 = N - 1, fact(N1,F1), F = F1 * N, !.
- 18 goal
a) fact(5,F)
F=120
YES
б) fact(4,24)
YES
в) fact(3,12)
NO
46. См. задание N 1 из 1.1.1. Значения M и N могут быть произвольными целыми числами.
47. См. задание N 2 из 1.1.1.
48. См. задание N 3 из 1.1.1.
49. См. задание N 5 из 1.1.1.
1.3.2. Рекурсивная обработка списковой информации
Представление информации в виде списка в ПРОЛОГ отличается от
представления в ЛИСП в первую очередь невозможностью представления
в одном списке разнотипной информации. Другой особенность является
невозможность прямого представления списка произвольной структуры
(в реализации PDC-Prolog). Поэтому при рекурсивной обработке списков имеется лишь рекурсия вширь, позволяющая обрабатывать элемент
за элементом до тех пор, пока список не станет пустым. Предикат,
определяющий пустоту списка, может быть представлен в виде элементарного факта empty, определение которого приведено в примере, или
непосредственно задаваться в конкретных правилах. Необходимо заметить, что при определении правил рекурсивной обработки списков переменные из списковых доменов в левой части правил, как правило,
являются более сложными списками, чем представленные в левой части
при рекурсивном вызове.
Рассмотрим организацию рекурсии при обработке списковой информации на примере объединения элементов двух списков в один. Тип
данных mylist, использованный в данном примере, задает домен, содержащий списки целых чисел. Тривиальными случаями, которые задаются фактами, являются случаи равенства какого-либо из двух входных
списков L1 или L2 пустому списку. В этом случае третий параметр L3
получает значение непустого списка. В случае, когда оба входных
списка имеют элементы, то результирующий список представляет из се-
- 19 бя список, в котором первый элемент совпадает с первым элементом
списка L1, а все остальные элементы получаются при объединении остатка первого списка со вторым. Рекурсивный вызов предиката
append редуцирует в данном случае входной параметр L1 до его тривиального случая.
domains
mylist = integer*
predicates
append(mylist,mylist,mylist)
empty(mylist)
clauses
empty([]).
append([],L2,L2).
append(L1,[],L1).
append([X|L1_rem],L2,[X|L3_rem]):-append(L1_rem,L2,L3_rem).
goal
append([1,2,3],[4,5],L3)
L3=[1,2,3,4,5]
YES
50. Определить предикат, распознающий списки-палиндромы, т.е.
списки, элементы которых одинаковы как при просмотре с начала, так
и с конца.
51. Найти последний элемент списка.
52. Найти количество и сумму элементов списка.
53. Найти максимальный элемент в заданном списке.
54. См. задание N 14 из 1.1.3.
55. В списке представлены составные объекты, содержащие информацию о книгах, имеющихся в библиотеке. Сформировать список, содержащий составные объекты, в которых задается информация об авторах
книг, объем которых превышает заданный, и количестве таких книг у
каждого автора.
1.3.3. Организация ввода-вывода
Работа с внешними носителями в ПРОЛОГ возможна с текстовыми и
двоичными файлами. Различаются файлы для чтения, для записи, для
модификации. В последнем случае возможны два варианта: выходной
- 20 файл может быть открыт либо для модификации любых записей, либо
только для добавления новых записей в конец файла. Обычно работа с
любым файлом выполняется в последовательном режиме, но возможна и
работа с записями в режиме прямого доступа к ним по номеру. В каждый момент времени может быть открыто произвольное количество файлов, но предикаты ввода-вывода работают с информацией только того
файла, который является активным в данный момент. Необходимо помнить, что предикаты открытия входного файла терпят неудачу при попытку открыть несуществующий файл. Точно так же терпят неудачу предикаты ввода, если выполняется считывание некорректной информации
(например, при попытке с помощью readint считать символьную информацию).
Рассмотрим пример организации ввода-вывода на примере визуализации вводимой из файла информации на экране монитора. Предикат
control_file организует выполнение вспомогательных операций (проверка существования входного файла, его открытие и активизацию, а
также закрытие по завершении работы) и вызов рекурсивного предиката
readfile, осуществляющего собственно считывание файла по записям и
их отображение на экране.
domains
filename=symbol
file=myfile
predicates
control_file(filename)
readfile
clauses
control_file(N):-existfile(N), openread(myfile,N),
readdevice(myfile), writedevice(screen),
readfile,
closefile(myfile), readdevice(stdin), !.
readfile:- readln(X), X<>"<*", !, write(X), readfile.
readfile.
goal
control_file("input.txt")
...............................................
отображение на экране информации из файла input.txt
...............................................
YES
- 21 56. Сформировать и записать на внешний носитель список чисел,
задаваемых с клавиатуры в диалоговом режиме.
57. Рассортировать исходный список чисел, созданный в предыдущем задании, на положительные и отрицательные числа, и записать их
на внешний носитель.
58. Исходный файл содержит множество составных объектов, содержащих информацию о различных предприятиях в разных городах.
Сформировать новые файлы, содержащие информацию о всех предприятиях
каждого города.
1.3.4. Динамическая база данных
Помимо статической информации, представленной в секции clauses
фактами и правилами, ПРОЛОГ обеспечивает возможность работы и с динамической информацией, задаваемой во внутренней базе данных и описываемой в секции database. Внутренняя база данных может содержать
только факты, причем их описание не должно повторяться в секции
predicates или других секциях database. ПРОЛОГ интерпретирует факты, принадлежащие внутренней базе данных, таким же образом, как
обычные предикаты. Рассмотрим пример применения внутренней базы
данных при вычислении факториала.
Фактически при вычислении N! вычисляются и все промежуточные
факториалы. При необходимости вычисления этой функции многократно
может быть более эффективно запоминать все вычисленные значения с
тем, чтобы в дальнейшем вычислять факториал лишь для новых (больших) значений, а для уже вычисленных ранее сразу брать их значение.
Вычисленные значения запоминаются в динамической базе данных в виде
фактов с именами factdb, а определение правила вычисления факториала в секции clauses задается именем fact. При попытке вычислить
значение факториаладля заданного числа сначала выполняется поиск в
динамической базе данных и лишь в случае неудачи начинается рекурсивное вычисление факториала. При этом на каждом шаге вновь проверяется содержимое динамической базы данных, так что процесс вычисления идет не до факта fact(0,1), а до факта factdb(N_Max,F_Max),
имеющегося в текущий момент. При вычислении недостающих значений
они автоматически добавляются в динамическую базу данных.
Предикаты loaddb и savedb позволяют загружать с внешнего носителя накопленную ранее базу данных факториала и запоминать в конце
работы пополненную.
- 22 database
factdb(integer,integer)
predicates
fact(integer,integer)
loaddb
savedb
clauses
loaddb:-existfile("factdb.dbp"), consult("factdb.dbp"), !,
not(factdb(0,1)), asserta(factdb(0,1)), ! ;
asserta(factdb(0,1)).
fact(N,F):- factdb(N,F),!;
N1=N-1, fact(N1,F1), F=F1*N, asserta(factdb(N,F),!.
savedb:-save("factdb.dbp").
59. См. задание N 15 из 1.1.3. Для хранения вычисленных чисел
Фибоначчи использовать динамическую базу данных.
60. Имеется база данных родственных отношений, описывающая одно семейство. Предусмотреть сохранение текущей информации на внешнем носителе после ее изменения в процессе работы.
61. См. задание N 37 из 1.2.2.
62. См. задание N 38 из 1.2.2.
.
- 23 2. ЗАДАНИЯ ДЛЯ ЛАБОРАТОРНЫХ ЗАНЯТИЙ
На лабораторных занятиях студенты получают практические навыки
работы с системами программирования на языках ЛИСП, ФРЛ и ПРОЛОГ,
отлаживая и тестирую программы и функции, указанные в задании. Каждая лабораторная работа рассчитана на 2 часа
2.1. Задания по языку программирования ЛИСП
ЛАБОРАТОРНАЯ РАБОТА N 1.
Реализовать задания N 1 - 5 из 1.1.1.
ЛАБОРАТОРНАЯ РАБОТА N 2.
Реализовать задания N 6 - 10 из 1.1.2.
ЛАБОРАТОРНАЯ РАБОТА N 3.
Реализовать задания N 11 - 15 из 1.1.3.
ЛАБОРАТОРНАЯ РАБОТА N 4.
Реализовать задания N 16 - 20 из 1.1.4.
ЛАБОРАТОРНАЯ РАБОТА N 5.
Часть 1. Реализовать задания N 21 - 25 из 1.1.5.
Часть 2. Входной файл на внешнем носителе содержит исходные
данные в виде множества допустимых в ЛИСП структур данных. Рассортировать его и записать на внешний носитель в виде четырех файлов,
каждый из которых содержит либо числовые атомы, либо символьные
атомы, либо точечные пары, либо списки.
ЛАБОРАТОРНАЯ РАБОТА N 6.
Реализовать задания N 26 - 30 из 1.1.6.
2.2. Задания по языку программирования ФРЛ
ЛАБОРАТОРНАЯ РАБОТА N 7.
Реализовать задания N 31 - 34 из 1.2.1.
- 24 –
ЛАБОРАТОРНАЯ РАБОТА N 8.
Реализовать задания N 36 - 38 из 1.2.2.
ЛАБОРАТОРНАЯ РАБОТА N 9.
Реализовать задания N 41 - 44 из 1.2.3.
ЛАБОРАТОРНАЯ РАБОТА N 10.
Часть 1. Реализовать задание N 35 из 1.2.1.
Часть 2. Реализовать задания N 39 - 40 из 1.2.2.
Часть 3. Реализовать задание N 45 из 1.2.3.
2.3. Задания по языку программирования ПРОЛОГ
ЛАБОРАТОРНАЯ РАБОТА N 11.
Реализовать задания N 46 - 49 из 1.3.1.
ЛАБОРАТОРНАЯ РАБОТА N 12.
Реализовать задания N 50 - 53 из 1.3.2.
ЛАБОРАТОРНАЯ РАБОТА N 13.
Реализовать задания N 54 - 55 из 1.3.2.
ЛАБОРАТОРНАЯ РАБОТА N 14.
Реализовать задания N 56 - 58 из 1.3.3.
ЛАБОРАТОРНАЯ РАБОТА N 15.
Реализовать задания N 59 - 60 из 1.3.4.
ЛАБОРАТОРНАЯ РАБОТА N 16.
Реализовать задания N 61 - 62 из 1.3.4.
.
- 25 3. ЗАДАНИЯ ДЛЯ КУРСОВОЙ РАБОТЫ
Курсовая работа выполняется студентами в 4-м семестре и включает в себя три раздела соответственно по языкам ЛИСП, ФРЛ и ПРОЛОГ. Каждый вариант содержит три задания, которые должны быть выполнены на ПЭВМ, и итоги отладки и тестирования должны быть представлены в виде отчета по курсовой работе.
На языке ЛИСП должны быть реализованы задание N 1 ( извлечение
информации из сложных структур данных с помощью рекурсивных функций) и задание N 2 ( построение новых структур данных ). При этом
задание N 2 должно быть реализовано тремя способами - а) рекурсивно; б) итерационно; в) с использованием функционала.
На языке ФРЛ должно быть реализовано задание N 3.
На языке ПРОЛОГ должны быть реализованы задания N 1 и 3.
Ниже приводятся варианты для выполнения курсовой работы.
ВАРИАНТ N 1.
1. Реализовать функции (@NTHCDR n list ) и (@NTH n list) , возвращающие соответственно n-й CDR и CAR от списка list. Некорректное
задание параметра n должно контролироваться.
Примеры: (@NTHCDR 0 '(А В С)) => (А В С)
(@NTHCDR 2 '(А В С D)) => (С D)
(@NTH 0 '(А В)) => А
(@NTH 1 '((АВ)(ВС)(CD)К)) => (ВС)
2. Реализовать функцию (@DELETE atom list) , возвращающую список list, в котором из всех подсписков удален атом atom.
Пример:
(@DELETE 'A '((A B C) (B C D A A) (C D) (A A)))
((B C) (B C D) (C D) NIL)
3. Реализовать функцию (WAY p1 p2), осуществляющую поиск на
заданном неориентированном графе любого пути между двумя вершинами
p1 и p2. Проверить работу функции WAY на примере фрагмента схемы
Московского метополитена (2 - 3 линии, 8 - 10 станций).
Пример для ФРЛ:
(DEFRAMEQ
- 26 –
ПРОЛЕТАРСКАЯ
(ВПЕРЕД ($VALUE (ТАГАНСКАЯ_РАДИАЛЬНАЯ)))
(НАЗАД ($VALUE (ВОЛГОГРАДСКИЙ-ПРОСПЕКТ))) )
(DEFRAMEQ
ТАГАНСКАЯ_РАДИАЛЬНАЯ
(ВПЕРЕД ($VALUE (ПЛОЩАДЬ-НОГИНА)))
(НАЗАД ($VALUE (ПРОЛЕТАРСКАЯ)))
(ПЕРЕСАДКА ($VALUE
(MAPKCИСТСКАЯ)(ТАГАНСКАЯ_КОЛЬЦЕВАЯ)))
.....
(WAY 'ПРОЛЕТАРСКАЯ 'ТУРГЕНЕВСКАЯ)
(ПРОЛЕТАРСКАЯ ТАГАНСКАЯ ПЛОЩАДЬ-НОГИНА
ТУРГЕНЕВСКАЯ)
ВАРИАНТ N 2.
1. Реализовать функции (@COUNT object list test) и (@COUNT-IF
test list) , возвращающие количество элементов в списке list, для
которых (test object element) есть не NIL. Здесь element - текущий
элемент списка list. Если аргумент test опущен, то test = EQUAL.
Для второй функции предикат test является одноместным.
Примеры: (@COUNT 'А '(А В С D А Е)) => 2
(@COUNT '5 '(2 9 -7 4) '>) => 3
(@COUNT-IF 'MINUSP '(3 -6 8 7 -2)) => 2
2. Реализовать функцию (@INSERT atom list) , возвращающую список list, в котором в начало каждого подсписка добавлен атом atom.
Пример: (@INSERT 'A '((B C) (B (C D)) (C D) NIL))
((A B C) (A B (A C D)) (A C D) (A))
3. Реализовать функцию (DIALOGUE), позволяющую в процессе диалога создавать сложные структуры данных (фреймы на ФРЛ, составные
объекты на ПРОЛОГ). При реализации функции на ФРЛ использовать процедуру FINSTANTIATE, а на ПРОЛОГ - динамическую базу данных. Проверить работу функции на примере заполнения личной карточки студента
(информация о фамилии, группе, имени, отчестве, дате рождения ).
Пример на ФРЛ:
(DIALOGUE)
УКАЖИТЕ ВАШУ УЧЕБНУЮ ГРУППУ
А-14-94
- 27 УКАЖИТЕ ВАШУ ФАМИЛИЮ
ИВАНОВ
. . .
ХОТИТЕ ПОСМОТРЕТЬ РЕЗУЛЬТАТЫ РАБОТЫ? (ДА/НЕТ)
ДА
-----------------------------(СТУДЕНТ*1
(ГРУППА ($VALUE (А-14-94 0)))
(ФАМИЛИЯ ($VALUE (ИВАНОВ)))
.....
)
-----------------------------ВАРИАНТ N 3.
1. Реализовать функции (@FINDLIST object list test ) и
(@FINDLIST-IF test list) , осуществляющие поиск на верхнем уровне в
списке list. В качестве результата возвращается список элементов из
list, для которых (test object element) не NIL. Здесь element - текущий элемент списка list. Если аргумент test опущен, то test =
EQUAL. Для второй функции предикат test является одноместным.
Примеры: (@FINDLIST 'A '(B C A B C A)) => (A A)
(@FINDLIST 5 '(1 0 -5 6 10) '<) => (6 10)
(@FINDLIST-IF 'MINUSP '(5 10 -3 -4)) => (-3 -4)
2. Реализовать функцию (@INSEND atom list), возвращающую список list, в котором в конец каждого подсписка добавлен атом atom.
Пример: (@INSEND 'A '((B C) (B (C) D) (C D) NIL))
((B C A) (B (C A) D A) (C D A) (A))
3. Реализовать функцию (ANALYSIS sentence) , позволяющую распознать синтаксически правильные предложения русского языка. Под
синтаксически правильными предложениями будем понимать те, в которых правильный порядок слов и все слова предложения имеются в словаре.
Проверить работу функции на примере словаря, содержащего 12 15 слов. Использовать грамматику простых повествовательных предло-
- 28 жений, содержащих подлежащее, сказуемое и, возможно, несколько определений.
Пример на ФРЛ:
(DEFRAMEQ
*ГРАММАТИКА*
(S1 ($VALUE ((ПРИЛАГАТЕЛЬНОЕ S1) (ПРИЛАГАТЕЛЬНОЕ S2))))
(S2 ($VALUE ((CУЩЕСТВИТЕЛЬНОЕ S3))))
.....
)
(DEFRAMEQ
СТОЛ
(ЧАСТЬ-РЕЧИ ($VALUE (CУЩЕСТВИТЕЛЬНОЕ))) )
.....
(ANALYSIS '(БОЛЬШОЙ СТОЛ СИНИЙ)) => NIL
(ANALYSIS '(БОЛЬШОЙ СИНИЙ СТОЛ)) => T
(ANALYSIS '(БОЛЬШОЙ СТОЛ ГОРИТ)) => T
ВАРИАНТ N 4.
1. Реализовать функции (@ASSOC key alist test) и (@ASSOC-IF
test alist) , осуществляющие поиск пары pair в ассоциативном списке
alist, для которой (test key (CAR pair)) не NIL. Если аргумент test
опущен, то test = EQUAL. Для второй функции предикат test является
одноместным.
Примеры: (@ASSOC 'А '(В D (A B)(C D))) => (A B)
(@ASSOC 5 '((1 2)(3 4)(6 8)) '<) => (6 8)
(@ASSOC-IF 'MINUSP '((2 3)(-3 4))) => (-3 4)
2. Реализовать функцию (@PRINTPOS list1 list2) , печатающую
элементы списка list1 каждый в отдельной строке, но с позиции, задаваемой соответствующим числом из списка list2. Если количество
элементов в списке list2 меньше необходимого, то он вновь просматривается сначала.
Пример: (@PRINTPOS '(A B C (B C D) NIL (E) END) '(1 2 3 4 5))
А
В
С
(B C D)
NIL
- 29 (E)
END
T
3. Реализовать функцию (LABYRINTH begin_point) , моделирующую
путешествие по лабиринту в процессе диалога.
Проверить работу функции на примере модели лабиринта из 10 12 комнат.
Пример на ФРЛ:
(DEFRAMEQ
KOM*1
(TEКСТ ($VALUE ("КОМНАТА1")))
(ВПЕРЕД ($VALUE (КОМ*2)))
(ВПРАВО ($VALUE (КОМ*5)))
)
.....
(LABYRINTH 'КОМ*1)
КОМНАТА1
ВЫБЕРИ НАПРАВЛЕНИЕ ДВИЖЕНИЯ (П,Л,В,Н)
Л
**** ТАКОГО ПУТИ НЕТ ****
В
КОМНАТА2
ВЫБЕРИ НАПРАВЛЕНИЕ ДВИЖЕНИЯ (П,Л,В,Н)
.....
*** ВЫ ВЫШЛИ ИЗ ЛАБИРИНТА ***
ВАРИАНТ N 5.
1. Реализовать функции (@FIND object list test) и (@FIND-IF
test list) , осуществляющие поиск на верхнем уровне в списке list. В
качестве результата возвращается элемент списка list, для которого
(test object element) не NIL. Здесь element - текущий элемент списка list. Если аргумент test опущен, то test = EQUAL. Для второй
функции предикат test является одноместным.
Примеры: (@FIND 'A '(B CA B C A)) => A
(@FIND 5 '(-10 -5 6 10) '<)) => 6
(@FIND-IF 'MINUSP' (5 10 -3 -4)) => -3
(@FIND-IF 'MINUSP' (5 10 4)) => NIL
- 30 2. Реализовать функцию (@PRINTBLNK list1 list2) , печатающую
последовательно элементы списка list1, но перед каждым элементом
списка list1 выводится количество пробелов, задаваемое соответствующим числом из списка list2. Если количество элементов в списке
list2 меньше необходимого, то он вновь просматривается сначала.
Пример: (@PRINTBLNK '(A B C (B C D) NIL) '(1 2 3 4))
A B C (B C D) NIL
T
3. Реализовать функцию (ANSWER question) , формирующую ответ на
вопрос по ключевым словам, содержащимся в нем.
Для представления знаний об ответе в ФРЛ можно использовать
фреймы, в которых ответы на вопрос хранятся в аспектах с именем
$VALUE, а список ключевых слов (для идентификации ответа) - в аспектах с именем $DEFAULT. В ПРОЛОГ для этой цели можно использовать
составные объекты.
Проверить работу функции на примере 5-6 наборов ключевых слов.
Пример на ФРЛ:
(DEFRAMEQ
ОТВЕТЫ
(ВОЗРАСТ ($VALUE (20))
($DEFAULT (CKOЛЬКО) (ЛЕТ) (ВОЗРАСТ)) )
(ИМЯ ($VALUE (ЖОРА))
($DEFAULT (КАК) (ЗОВУТ) (ИМЯ))
)
......
)
(ANSWER '(КАК ТЕБЯ ЗОВУТ ?)) => ЖОРА
(ANSWER '(СКОЛЬКО ТЕБЕ ЛЕТ ?)) => 20
(ANSWER '(ТЫ ЛЮБИШЬ ДЕТЕКТИВЫ ?)) => НЕ ЗНАЮ
ВАРИАНТ N 6.
1. Реализовать функции (@POSITION object list test) и
(@POSITION-IF test list) , осуществляющие поиск на верхнем уровне в
списке list. В качестве результата возвращается номер элемента
списка list, для которого (test object element) не NIL. Здесь
element - текущий элемент списка list. Если аргумент test опущен,
то test = EQUAL. Для второй функции предикат test является одноместным.
- 31 Пример:
(@POSITION '(A B C) '((A)(A B C)(B) D)) => 2
(@POSITION '3 '(5 7 -7 4) '>) => 3
(@POSITION-IF 'MINUSP (1 2 -5 1)) => 3
2. Реализовать функцию (@PRINTMIXT list1 list2) , печатающую
последовательно элементы списка list1, но при этом перед каждым
элементом списка list1 выводится соответствующий элемент из списка
list2. Если количество элементов в списке list2 меньше необходимого, то он вновь просматривается сначала.
Пример: (@PRINTMIXT '(1 2 3 4 5 6 7) '(A B C D) )
A1 B2 C3 D4 A5 B6 C7
T
3. Реализовать функцию управления роботом (PUT-ON object1
object2) , позволяющую "переставлять" предмет object1 с текущего
места на предмет object2. Если предмет находится не на поверхности
(т.е. на нем стоит другой предмет), то его переставить нельзя.
При реализации на ФРЛ необходимо использовать присоединенные
процедуры $IF-ADDED и/или $IF-REMOVED, а при реализации на ПРОЛОГ
- динамическую базу данных.
Пример на ФРЛ:
(DEFRAMEQ КУБ*2
(НАД ($VALUE (ШАР*3))
($IF-ADDED . . .))
(ПОД ($VALUE (ПИРАМИДА*5))
($IF-REMOVED . . .)) )
......
(PUT-ON 'КУБ*2 'БЛОК*1) => NIL
(PUT-ON 'ШАР*3 'БЛОК*1) => T
ВАРИАНТ N 7.
1. Реализовать функции (@SUBLIST list n m ) и (@SUBLIST-IF list
n m test ), выделяющие из списка list элементы с порядковыми номерами от n до m и возвращающими их в виде результирующего списка. Вторая функция включает в результирующий список лишь те элементы list,
для которых (test element) не NIL. Если test опущен, то включаются
все необходимые элементы.
- 32 Пример: (@SUBLIST '(A B C D E F) 3 5) => (C D E)
(@SUBLIST '(A B C D) 4 4) => (D)
(@SUBLIST-IF '(A 1 C 2 E 3) 2 6 'SYMBOLP) => (C E)
2. Реализовать функцию (@X list1 list2) , возвращающую список,
отображающий декартово произведение исходных списков произвольной
длины.
Пример: (@X '(A1 A2) '(B1 B2 B3))
((A1 B1) (A2 B1) ... (A1 B3) (A2 B3))
3. Пусть конечный автомат задается множеством фреймов F={F1,
F2, ... FN}, причем каждый Fi имеет вид:
<Fi>::= (Fi
(OUTPUT ($value (<выходное сообщение>)))
(<входное сообщениеi1> ($value (Fi1)))
.............
(<входное сообщениеik> ($value (Fik)))
(TERMINATE ($value (<конечная вершина> ...) )
<входное сообщение>::= <атом>
<выходное сообщение>::=<атом>
Написать функцию (LIFE begin list ), отображающую поведение автомата с начальной точки begin под действием списка входных сообщений list. Результатом функции должен быть список выходных сообщений
автомата.
ВАРИАНТ N 8.
1. Реализовать функции (@SUBSTITUDE new old list test ) и
(@SUBSTITUDE-IF new test list) , возвращающие в качестве результата
список list, в котором все элементы, для которых (test old element)
не NIL. заменяются на new. Здесь element - текущий элемент списка
list. Если аргумент test опущен, то test = EQUAL. Для второй функции предикат test является одноместным.
Примеры:
(@SUBSTITUDE 5 2 '(3 4 2 8 5 2)) > (3 4 5 8 5 5)
(@SUBSTITUDE 5 4 '(3 4 2 8 5 2) '>=) => (5 5 5 8 5 5)
(@SUBSTITUDE-IF '0 'MINUSP (3 4 -5 8 -3)) => (3 4 0 8 0)
2. Реализовать функцию (@LISTFILT list test), создающую список
- 33 из элементов исходного списка list, включая в него только те элементы списка list, которые удовлетворяют предикату test.
Пример: (@LISTFILT '(A 1 B 2 C 3 D) 'SYMBOLP)
(A B C D)
3. Учащийся сдает экзамены по нескольким предметам. Организовать базу знаний таким образом, чтобы при занесении результата очередного экзамена автоматически рассчитывался текущий средний балл.
При реализации на ФРЛ использовать механизм присоединенных
процедур, а при реализации на ПРОЛОГ - динамическую базу данных.
ВАРИАНТ N 9.
1. Реализовать функции (@MEMBER item list test) и (@MEMBER-IF
test list), осуществляющие поиск в списке list и возвращающие остаток списка list начиная с того элемента, для которого (test item
element) не NIL. Здесь element - текущий элемент списка. Если аргумент test опущен, то test = EQUAL. Для второй функции предикат test
является одноместным.
Пример: (@MEMBER 'A '(B C DD A B A)) => (A B A)
(@MEMBER 5 (3 4 8 1 3) '<) => (8 1 3)
(@MEMBER-IF 'NUMBERP '(A B 3 4 C 5) => (3 4 C 5)
2. Реализовать функцию (@LISTMIXT list1 list2), образующую
список, каждый элемент которого является списком list1 без одного,
двух и т.д. элементов, причем первый элемент заменен на соответствующий элемент списка list2. Если количество элементов в списке
list2 меньше необходимого, то он вновь просматривается сначала.
Пример: (@LISTMIXT '(A B C D) '(1 2 3))
((1 B C D) (2 C D) (3 D) (1))
3. Реализовать функцию (RETURN-DEBT who amount ) , позволяющую
при поступлении наличных денег раздавать долги насколько это возможно. Проверить работу функции на базе знаний о 5 - 6 людях, имеющих в том числе и взаимные долги ( возможно, неявные ). При работе
функции долги должны отдаваться всеми до тех пор, пока это возможно.
Пример на ФРЛ:
(DEFRAMEQ
- 34 ИВАНОВ
(НАЛИЧНЫЕ ($VALUE (10)))
(ДОЛГИ ($VALUE (ПЕТРОВ)(CИДОРОВ)))
(ПЕТРОB ($VALUE (20)))
(CИДОРОВ ($VALUE (15))) )
. . . . .
(RETURN-DEBT 'ИВАНОВ 15) => T
. . . . .
(FPRINT '(ИВАНОВ))
-----------------------------(ИВАНОВ
(НАЛИЧНЫЕ ($VALUE (0)))
(ДОЛГИ ($VALUE (СИДОРОВ)))
(СИДОРОВ ($VALUE (10))) )
-----------------------------ВАРИАНТ N 10.
1. Реализовать функции (@CHAR atom n ) и (@FINDCHAR atom
char n ) . Первая возвращает n-ый символ атома atom, а вторая возвращает
номер позиции первого вхождения char в atom, при этом n задает номер позиции в atom, начиная с которой необходимо выполнять поиск.
Если n опущено, то поиск начинается с начала аtom.
Пример: (@CHAR 'ABCD 3) => C
(@CHAR 'ABC 10) => NIL
(@FINDCHAR 'ABCDEFCD 'D) => 4
(@FINDCHAR 'ABCDEFCD 'D 5) => 6
2. Реализовать функцию (@INTERSECT list1 list2) , возвращающую
список list1, в котором оставлены только элементы, входящие в список list2.
Пример: (@INTERSECT '(A B C D E) (B D A A))
(A B D)
3. Реализовать базу знаний для родственных отношений. Должны
отслеживаться отношения: отец, мать, сын, дочь, бабушка, дедушка,
муж, жена, внук, внучка, теща, свекровь. Предусмотреть автоматическую корректировку всех родственных связей при занесении единичной
информации о новом человеке.
- 35 ВАРИАНТ N 11.
1. Реализовать функции (@FIRSTN n list ) и (@BUTLAST list n) ,
возвращающие в качестве результата список из n первых элементов
списка list и список без последних n элементов списка list. Если n
задано некорректно, то возвращается пустой список.
Примеры: (@FIRSTN -5 '(A B)) => NIL
(@FIRSTN 2 '(A B C)) => (A B)
(@FIRSTN 3 '(A B)) => (A B)
(@BUTLAST '(A B C D) 2) => (A B)
2. Реализовать функцию (@PRINTFILT list test) , печатающую последовательно с новой строки только те элементы списка list, которые
удовлетворяют предикату test.
Пример: (@PRINTFILT '(A 1 B 2 C 3 D) 'NUMBERP)
1
2
3
(A 1 B 2 C 3 D)
3. Реализовать диалоговую функцию (ПОИСК) . Семантика: функция
ПОИСК работает с базой знаний, реализующей фрагмент семантической
сети, описывающей мир животных (для примера взять сеть с 8-10 вершинами). ПОИСК задает вопросы, позволяющие идентифицировать об'екты
в семантической сети по их признакам.
Для представления знаний в ФРЛ следует использовать механизм
наследования по АКО-иерархии, а в ПРОЛОГ - динамическую базу данных. Предусмотреть возможность занесения новой и удаления старой
информации.
Пример на ФРЛ:
(DEFRAMEQ
*КОРН.ВЕРШ*
(INSTANCE ($VALUE (ПТИЦЫ) (РЫБЫ) ...))
)
(DEFRAMEQ
ПТИЦЫ
(АКО ($VALUE (*КОРН.ВЕРШ*)))
(INSTANCE ($VALUE (ВОДОПЛАВАЮЩИЕ) ...))
- 36 (КРЫЛЬЯ($VALUE (ECTЬ))
(ЧЕШУЯ ($VALUE (НЕТ)))
(ТЕМП-ТЕЛА ($VALUE (40)))
(ПОСТОЯН-ТЕМПЕР-ТЕЛА ($VALUE (ДА)))
)
(DEFRAMEQ
ВОДОПЛАВАЮЩИЕ
(АКО ($VALUE (ПТИЦЫ)))
(INSTANCE ($VALUE (УТКА)(ГУСЬ) ...))
...
)
(DEFRAMEQ
ГУСЬ
(АКО ($VALUE (ВОДОПЛАВАЮЩИЕ)))
...
)
(ПОИСК)
ТЕМПЕРАТУРА ТЕЛА ПОСТОЯННАЯ? (ДА/НЕТ)
ДА
...
КРЫЛЬЯ ИМЕЮТСЯ? (ДА/НЕТ)
ДА
...
ЭТО - ГУСЬ
*КОНЕЦ*
ВАРИАНТ N 12.
1. Реализовать предикат (@NUM-SORT-P list test) , который равен
T, если элементы списка list последовательно попарно удовлетворяют
условию test. Если аргумент test опущен, то test = EQUAL.
Пример: (@NUM-SORT-P '(5 2 3/4 7 0 3 -4) '<) => NIL
(@NUM-SORT-P '(-4 0 0.75 2 3 5 7) '<) => T
2. Реализовать функцию (@CASE-OF <селектор> <вариант1> ...
<вариантN> ) - аналог оператора CASE языка Си. Каждый вариант имеет
вид <случай> <форма>, где <случай> ::= <S -выражение>. Сначала вычисляется значение селектора. Затем среди вариантов ищется первый,
у которого случай совпал (EQL) со значением селектора. Результатом
- 37 функции будет значение соответствующей формы.
3. Реализовать небольшую поисковую систему по вариантам обмена
жилой площадью. На входе такой системы - описание требуемого варианта обмена, на выходе - список подходящих вариантов. Предусмотреть
базу вариантов на 10-15 единиц.
Пример на ФРЛ:
(DEFRAMEQ Вариант-обмена-1
(AKO ($VALUE (Вариант-обмена)))
(число комнат ($value (3)))
(общая-площадь ($require (> :value 35)))
(расположение ($value (центр) or (ст.м.Полежаевская)))
(этаж ($require (> :value 1) (neq :value 'последний)))
...........
)
.
- 38 -
ЛИТЕРАТУРА
1. Уэно Х., Кояма Т. и др. Представление и использование знаний. - М.: Мир, 1989, 220 стр.
2. Семенова Е.Т. Язык программирования ЛИСП 1.5 - М.: МЭИ,
1977, 100 стр.
3. Э.Хювенен, Й.Сеппянен. Мир Лиспа. В 2-х томах - М.: Мир,
1990.
4. Байдун В.В.,Кружилов С.И. и др., Программирование на языке
ЛИСП в системе muLISP-90 - М.: МЭИ, 1994, 40 стр.
5. Семенова Е.Т. Представление знаний в системе LISP/FRL.
- М.: МЭИ, 1987, 104 стр.
6. Байдун В.В., Бунин А.И. и др., Языки и системы представления знаний ( язык программирования ФРЛ) - М.: МЭИ, 1994, 44 стр.
7. Вагин В.Н., Головко А.В. Язык программирования Турбо-Пролог - М.: МЭИ, 1992, 104 стр.
8. Братко И., Программирование на языке ПРОЛОГ для искусственного интеллекта: Пер. с англ. - М.: Мир, 1990, 560 стр.
.
- 39 -
Содержание
ВВЕДЕНИЕ ............................................... 3
1. ЗАДАНИЯ ДЛЯ ПРАКТИЧЕСКИХ ЗАНЯТИЙ ....................... 4
1.1. Задания по языку программирования ЛИСП ............... 4
1.1.1. Рекурсивная обработка числовой информации .......... 4
1.1.2. Рекурсивная обработка списковой информации ........ 5
1.1.3. Конструирующая рекурсия ............................ 7
1.1.4. Последовательные, циклические и итерационные
вычисления ......................................... 8
1.1.5. Функционалы ........................................ 9
1.1.6. Ассоциативные списки и списки свойств ..............10
1.2. Задания по языку программирования ФРЛ ................11
1.2.1. Создание фреймов и извлечение информации из них ....11
1.2.2. Присоединенные процедуры ...........................12
1.2.3. Организация сетей фреймов ..........................14
1.3. Задания по языку программирования ПРОЛОГ .............16
1.3.1. Рекурсивная обработка числовой информации ..........17
1.3.2. Рекурсивная обработка списковой информации ........18
1.3.3. Организация ввода-вывода ...........................19
1.3.4. Динамическая база данных ...........................21
2. ЗАДАНИЯ ДЛЯ ЛАБОРАТОРНЫХ ЗАНЯТИЙ .......................23
2.1. Задания по языку программирования ЛИСП ...............23
2.2. Задания по языку программирования ФРЛ ................23
2.3. Задания по языку программирования ПРОЛОГ .............24
3. ЗАДАНИЯ ДЛЯ КУРСОВОЙ РАБОТЫ ............................25
Литература ................................................38
.
- 40 -
В.В.Байдун, П.Л.Чернов
Методические указания по курсу
Языки и методы программирования
СБОРНИК ЗАДАНИЙ ПО ПРОГРАММИРОВАНИЮ
НА ЯЗЫКАХ ЛИСП, ФРЛ И ПРОЛОГ
(Кафедра Прикладной математики)
Редактор П.Л.Чернов
Редактор издательства
_____________________________________________________________
Темплан издания МЭИ 1996 г.(II), метод.
Подписано к печати
Формат 60x84/16
Физ.печ.л.
Уч.-изд.л.
Тираж
Изд N
Заказ
_____________________________________________________________
Типография Издательства МЭИ, ротапринт, Красноказарменная, 13
Download