Краткие теоретические сведения. 2.1 Структуры Пролога
2.1 Структуры Пролога Для представления структурированных (составных) данных в Прологе используются списки и структуры. Близким аналогом прологовских структур в алгоритмических языках (например, Си и Паскаль) являются записи. Важной особенностью структур, обуславливающей их широкое. применение, является компактное представление сложно организованных данных. Структуры - это объекты, которые состоят из нескольких компонент, возможно разных типов. Этими компонентами могут быть константы, переменные и, в свою очередь структуры. Определение, которое использует внутри себя определяемое понятие называется рекурсивным. Таким образом, структура есть рекурсивный тип данных. Структура состоит из функтора (имени) и последовательности компонент, заключенных в круглые скобки и разделенные запятой. Например: date(1, "май", 1996) - определяет дату 1 мая 1996 года; date(X, Y, 1996) - определяет произвольный день 1996 года; person(fam("Иванов", "Петр", 'Сергеевич".), "г. Уфа, ул. Ленина, дом 100, кв. 25", "50-49-01") . /*определяет сложный объект сведения о человеке: имя лица, адрес, домашний телефон, где имя, в свою очередь, является структурой содержащий три компоненты: фамилию, имя, отчество.*/ Последний пример - пример вложенной структуры, когда одна из компонент структуры является структурой. Это первый уровень вложенности. Если вложенная структура имеет компоненту, которая, в свою очередь, является структурой, то это будет второй уровень вложенности и так далее. Количество уровней вложенности в языке Пролог не оговаривается. Число компонент структуры называется размерностью структуры или арностыо структуры. Две структуры имеют идентичную организацию, если у них одинаковые функторы и размерность. Пролог допускает структуры с разным числом компонент и одинаковыми функторами. Это будут структуры с разной организацией. 2.2 Описание структур в Турбо-Прологе Турбо-Пролог требует описания используемых структур. Это осуществляется в разделе domains введением имени домена (имени типа) для структур с идентичной организацией. При этом после функтора в скобках указываются имена домена (тины компонент). Например: domains data=date(day, month, year) month=string day, year = integer person=person(name, address, telno) address, telno=string name=(string, string, string) Введенные имена домен структур используются далее в программе при описании предикатов, имеющих в качестве аргументов эти структуры. Имя домена и функтор могут - совпадать (person). Турбо-Пролог различают их из контекста.
2.3 Альтернативные домены В общем случае описание типов структур в Турбо-Прологе выглядит следующим образом: <domain>=<alternative1>(D11, D12...); <alternative2>(D21, D22); где domain — имя типа /имя домена/ alternative1 и alternative2 — равноправные, но различные функторы (D11, D12...) и (D21, D22) — список типов компонент структур (типы стандартные и определяемые пользователем) Каждая альтернатива включает функтор и, возможно, список областей для соответствующих компонент. Альтернативные домены позволяют вводить общее имя типа данных для структур с разными именами (функторами) Это дает возможность определить единый предикат, обрабатывающий эти разнородные структуры. В случае отсутствия такой возможности пришлось бы определять свои предикаты обработки структур -для каждой альтернативы.
2.4 Встроенные предикаты ввода/вывода и некоторые другие Турбо-Пролог обладает достаточно широкой библиотекой встроенных предикатов, обеспечивающих ввод и вывод данных. - readln(X) Переменная Х - строковая или символьная, должна быть свободной перед выполнением предиката. Вводимая строка должна заканчиваться нажатием клавиши Enter. - readint(X) Переменная Х должна быть целой. Символы вводятся до нажатия клавиши Enter. Если вводимая строка не соответствует целому числу, то выполнение предиката readint прерывается и вырабатывается ошибка. - readreal(X). Переменная Х должна, быть вещественной. Символы вводятся до нажатия клавиши Enter. Если вводимая строка не соответствует синтаксису вещественного числа, то возникает ошибка. - readchar(Х). Переменная Х должна быть символьной Предикат readchar считывает отдельный символ с текущего устройства ввода. - file_str(X). Переменные F и Х являются строковыми, F - имя файла в DОS, Х - свободная переменная. Предикат file_str читает данные из файла, пока не будет введен символ конца строки файла ([Ctrl]+[Z]). Содержимое файла F пересылается в Х. Считываемый файл не должен превышать 64 Кб. - readterm(D, Т) Используется для чтения объектов, относящихся к определенному в программе домену D. Т - свободная переменная, которая получает вводимые значения - write(Arg1, Arg2...). Аргументами Arg1, Arg2,... Могут быть как константы, так и переменные. Предикат осуществляет вывод значений аргументов на текущее записывающее устройство (по умолчанию - экран). - nl Предикат осуществляет переход на новую строку на текущем записывающем устройстве. - findall(X, P(...Х...),L) Х - переменная и является одним из аргументов предиката Р, когда он может быть выполнен успешно. -writef("string",Arg1,Arg2,...). Предикат осуществляет форматированный вывод информации. Вид выводимой информации определяется строкой "string". Для каждого из аргументов в строке присутствует спецификатор, определяющий место для выводимого значения и его форму. Общий вид спецификатора: %[-]m[.p][type] или %[[-]m[.p]type] где квадратные скобки означают, что соответствующая компонента может отсутствовать; m -целое, определяющее минимальную ширину поля, отводимого под значение. Если размер поля недостаточен, то отводится столько, сколько необходимо, 'дефис'- выравнивание выводимого значения на левую границу поля; p - целое, определяющее количество знаков после запятой у вещественных значений; type - тип выводимого значения, может иметь вид: d - вывод в десятичном представлении значений типа char и integer, х - вывод в шестнадцатеричном представлении значений типа char и: integer. u - вывод в беззнаковом десятичном представлении значений типа char и integer; c - вывод в виде символа значений типа char и integer; s - вывод в строковом виде значений типа symbol и string; f - вывод вещественных значений в форме с фиксированной точкой; е - вывод вещественных значений в экспоненциальной форме; g - вывод вещественных значений по форме f или е. Выбирается та форма, которая требует поля меньшей длины. Строка "string" может содержать управляющие символы: \n - переход на новую строку; \t - знак табуляции (пропуск определенного числа позиций); \nnn - вывод символа с кодом nnn; fail - константа неуспех (ложь); true - константа успех (истина); not(p) - завершается успешно, если предикат Р представляет цель, который является невыполнимой, и наоборот.
2.5 Примеры обработки структур и организации ввода/вывода 2.5.1 Формирование списка структур В программе в виде фактов info хранится информация о результатах тестирования ряда лиц. Тест содержал 11 вопросов. Порядок задания вопросов мог варьироваться. Тестируемый мог ответить на вопрос (верно или неверно) или не отвечать. Ответы на тест представлены в виде списка, содержащего 1, если ответ верен, и 0, если ответ неверен. У разных лиц списки могут бить различной длины: от пустого (не смог ответил ни на один вопрос) до списка, содержащего одиннадцать элементов. Информация: лицо и его ответы представлены в виде структуры. Требуется найти тех, кто ответил более чем на половину вопросов и сформировать из них список структур . domains test=t(name, result) name=string result=integer* number=integer* list=test* predicates info (number, test). len(result). р(test). do(list). clauses info(1, t("tom",[1, 0, 1, 1, 0]). info(2, t("bob",[]) info(3, t("ann",[0, 0, 1, 1, 1, 1, 0]). p(t( _, X)):-info( _, t( _, X)), len(X, N), N>3. len([], 0). len([Н|Т], N):-len(T, N1), N=N1+1. dо(L):- findall(X, р(X), L). С помощью предиката р выявляются лица, ответившие более чем на половину вопросов. Предикат len используется для определения длины списка ответов. Цель программы: предикат do формирует список структур, удовлетворяющий требованиям задачи.
2.5.2 Предикат управлении курсором В приведенной программе вводятся функторы для обозначения различных горизонтальных и вертикальных перемещений курсора по экрану. В примере используется встроенный предикат управления курсором cursor(Row, Column), который перемещает курсор в позицию (Row - строка, Column - столбец) экрана. Если Row и Column свободные переменные, то они получают значение текущей позиции курсора. domains step =integer movement =up(step); down(step); left(step); right(step); nо predicates move cursor(movement). clauses move_cursor(up(step)):-.cursor(R, C), R1=R-step, cursor(R1, С). move_cursor(down(step)):-cursor(R, С), R1=R+stер, cursor(R1, С). move_cursor(left(step)):-cursor(R, С), C1=C-step, cursor(R, C1). move_cursor(up(step)):-cursor(R, С), С1=С+stер, cursor(R1, C1). move_cursor(nо):-cursor(R. С). Функторы структур определяют направление перемещения курсора по экрану от его текущего положения uр - вверх, down-вниз, left - влево, right - вправо, nо - на месте. Величину перемещения определяет компонента структуры step-шаг. С помощью домена movement (движение), описывающего различные виды перемещения курсора по экрану, вводится предикат move_cursor — переместить курсор, осуществляющий перемещение курсора на указанное число позиций step в указанном направлении (за счет выбора функтора ). Перемещение курсора выполняется следующим образом: определяется текущее положение курсора (cursor(R, C)), вычисляется новое положение курсора ((R1, C) или (R, С1)); производится перемещение курсора в новое положение (cursor(R1, С) или cursor(R, С1))
2.5.3 Пример ввода и вывода элементов списка Требуется ввести ряд целых чисел, сформировать из них список, вывести его на экран как единое целое и поэлементно. domains list=integer* predicates input(list, list). read(list, list). loop(list, list). print(list). work. clauses work:-input([], L), nl, nl, write("Список L=", L), nl, nl, write("Состоит из элементов:"), nl, print(L). input(L, L2):-write("Введите элемент:"), read(L, L1), write( "Будете еще вводить? (y/n):"), loop(L1,L2). read(L[Х|L]):-readint(X),! read(L, L). loop(L, L):-readchar(Ch), Ch='n',! loop(L1,L2):-nl, input(L1, L2). print([X|L]):-write(X), nl, print(L) print([]). Предикат work осуществляет всю необходимую по условию задачи работу. Предикат input(L1, L2) вводит данные и, включая их в исходный список L1 , формирует выходной список L2. Ввод элемента и включение его в список осуществляется оператором read. Если при вводе элемента произошла ошибка то исходный список сохраняется. Предикат input после ввода каждого элемента спрашивает о продолжении ввода. Если ввод окончен, то необходимо нажать клавишу 'n'. Анализ введенного символа и выбор последующих действий осуществляет оператор loop. Предикат print осуществляет поэлементный вывод списка.
2.5.4 Пример ввода структурных данных и их обработка Требуется ввести для ряда лиц данные в виде e структуры, содержащей имя и возраст, и подсчитать средний возраст. domains person=p(name, age) name=string. age,sum=integer mean=real predicates readperson(person). run(sum, sum, sum, sum). do(mean). clauses readperson(p(Name, Age)):-write("Имя:" ), readln(Name)< write("Возраст:" ), readint(Age). run(S, N1, S2, N2):-write("Будете вводить? (у/и)"), readchar(Ch), nl, Ch=' у ', !, readperson(p( _, А)), S1=S+A, N1=N1+1, run(S1, N1, S2, N2). run(S, S, N, N). do(V):-run(0, S, 0,N), N<>0, !, nl, V=S/N. do(0). Предикат readperson осуществляет ввод данных, касающихся одного лица, формирует из них структуру р(Name, Age). Предикат run спрашивает о наличии сходных данных. Для подтверждения необходимо нажать клавишу ' у '. В противном случае следует нажать любую другую клавишу, что приведет к прекращению ввода. При наличии исходных данных происходит их ввод с помощью предиката readperson. Введенный возраст (А) прибавляется к накапливаемой сумме возрастов: S - значение суммы до ввода текущего данного, S1- сумма после ввода и прибавления А к S, счетчик числа введенных данных увеличивается на единицу (N - количество данных до ввода, N1- после ввода). В рассмотренном примере для ввода структуры вместо предиката readperson можно было бы воспользоваться встроенным предикатом readterm. Тогда изменение программы состояло бы в следующем: убрать из программы описание и определение предиката readperson; в предикате run заменить вызов readperson(р( _, А)) на readterm(person,р(_, А)); исходные данные набирать с указанием функтора (имени структуры), например p("Сергей", 18).
Популярное: Почему стероиды повышают давление?: Основных причин три... Как построить свою речь (словесное оформление):
При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою... Почему человек чувствует себя несчастным?: Для начала определим, что такое несчастье. Несчастьем мы будем считать психологическое состояние... Как выбрать специалиста по управлению гостиницей: Понятно, что управление гостиницей невозможно без специальных знаний. Соответственно, важна квалификация... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (387)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |