Настройка модема для программы пролог

Списки в Prolog

Списки — важная структура в Прологе. Списки позволяют хранить произвольное количество данных. Связный список — структура данных, состоящая из узлов. Узел содержит данные и ссылку (указатель, связку) на один или два соседних узла. Списки языка Prolog являются односвязными, т.е. каждый узел содержит лишь одну ссылку. Приложу наглядную картинку.

Кстати, ещё одна хорошая статья про списки в Прологе.

Списки в Прологе отличаются от списков в C/C++, Python и других процедурных языков. Здесь список — это либо пустой элемент; либо один элемент, называемый головой, и присоединенный список — хвост. Список — это рекурсивная структура данных с последовательным доступом.

Списки выглядят так: [],, , , , .Рассмотрим . Это всё список, в котором мы выделяем первый элемент, голову списка, и остальную часть, хвост списка. Чтобы отделить первые элементы от остальной части списка, используется прямая черта «|». Можно было написать такой список . Тогда мы выделим первые три элемента списка и положим их в X1, X2, X3, а остальная часть списка будет в Tail.

В списках хранятся данные, и нам нужно с ними работать. Например, находить минимум, максимум, медиану, среднее, дисперсию. Может нужно найти длину списка, длину самого длинного атома, получить средний балл по N предмету среди студентов группы G. Может нужно проверить, есть ли элемент Elem в списке List. И так далее. Короче, нужно как-то работать со списками. Только предикаты могут обрабатывать списки (да и в целом в Прологе все обрабатывается предикатами).

Напишем предикат для перебора элементов списка, чтобы понять принцип работы списка.

element(,Element) будет истинным, если Element равен Head (первому элементу списка) ИЛИ если предикат element(Tail, Element) истинный. В какой-то момент эта рекурсия окончится. (Вопрос читателю: когда кончится рекурсия? Какое условие будет терминирующим?) Таким образом, предикат будет истинным, если Element будет равен каждому элементу списка . Пролог найдет все решения, и мы переберем все элементы списка.

Часто бывает нужным знать длину списка. Напишем предикат для нахождения длины списка. Протестим.

Мой Пролог предупреждает, что была не использована переменная H. Код будет работать, но лучше использовать анонимную переменную _, вместо singleton переменной.

В SWI Prolog имеется встроенный предикат length. Я реализовал аналогичный предикат list_length. Если встречается пустой список, то его длина равна нулю. Иначе отсекается голова списка, рекурсивно определяется длина нового получившегося списка и к результату прибавляется единица.

Чтобы лучше понять алгоритм, пропишите его на бумаге. Последовательно, так, как делает Пролог.

Последняя задача про списки в этой статье, это определить, принадлежит ли элемент списку. Например, 1, 2, 3 и 4 являются элементами списка . Этот предикат мы назовем list_member.

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

Факты и правила

Часто программу, написанную на Прологе, называют базой знаний.

База знаний на Прологе состоит из предложений, т.е. утверждений, каждое из которых завершается точкой.
Существует два вида предложений: факты и правила.

Предложения-правила имеют вид:

B1,… , Bn.

Где  — это заголовок или голова предложения, а  – это тело.

Пример факта:

likes  (bill, dogs).

где — факт, — аргументы факта, между которыми выполнено отношение ()

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

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

Если факт состоит только из заголовка, то можно сказать, что факт – это предложение, у которого тело пустое.

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

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

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

В следующем примере наводите курсор на части конструкций, и появится подсказка:

Таким образом, в примере — это имя двухаргументного предиката (факта), у которого строковая константа «» является первым аргументом, а «» — вторым аргументом.

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

Задание prolog 2_2: Дано начало программы (раздел и ) для базы данных «Возраст ребенка». Составить факты для программы, основываясь на данных указанных разделов и следующих сведений: Ивану 2 года, Алексу 3 года, Марии — 5 лет.

domains 
  a=symbol
  b=integer
predicates
  age(a,b)
clauses
 age(...,...).
 ...(...,...).
 ...(...,...).

Наберите код программы в компиляторе.

Булевы значения

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

domains
  direction = left(); right()
  orientation = horizontal(); vertical()

Если у Вас есть булевские переменные, то именуйте их для условия истина. Так, переменная, выражающая то, что что-то опубликовано если она имеет значение истина (true) и не опубликовано, если она имеет значение ложь (false), должна называться Опубликовано.

Исключения и обработка ошибок

  • Когда происходит ошибка или исключительная ситуация, возбудите исключительную ситуацию с помощью exception::raise.
  • Блокируйте (trap) исключения если Вы хотите их обрабатывать.
  • Используйте finally если необходимо выполнить некоторый код даже при возникновении исключения, и уже затем продолжите исключение.
  • Ознакомьтес с руководством по обработке исключений.

Внутренние и прочие ошибки

Следует различать внутренние ошибки и ошибки, связанные с использованием пакета, модуля, класса, компоненты. Если нарушается внутренняя инвариантность, то это внутренняя ошибка. Типичными примерами внутренних ошибок являются:

  • Факт базы данных, который должен быть определён, не определён на самом деле.
  • Предикат, который должен бы быть процедурой, но компилятор не способен это распознать, преобразован в процедуру путём добавления «холостого» клауза. Если такой кляуз достигается, то это происходит от того, что предположение о том, что предыдущий клауз не может завершиться не успешно, было неверным.

Внутренние ошибки должны генерировать по одному исключению на каждую. Использование исключений следует по принципу: по одному на каждую ошибку пользователя и по одному на каждую внутреннюю ошибку.

Типичные пользовательские ошибки:

  • Выход индекса за допустимый диапазон
  • «неправильный» указатель на окно
  • нарушение порядка следования предикатов

Блокировка (try/catch) завершения программы может быть предусмотрена по двум причинам:

  • Есть желание обработать исключение. Скажем, при открытии файла возникает прерывание, сообщающее, что файл не существует. В этом случает возникает желание блокировать завершение программы и показать некоторое сообщение об ошибке, говорящее о том, что файл не существует. Естественно, если такое исключение не является единственно возможным, то следует продолжить исключение.
  • Есть желание что-то сделать независимо от того, прерывается ли выполнение предиката. Типичный пример — Вы что-блокируете (захватываете ресурс), затем что-то делаете и, наконец, сбрасываете блокировку (освобождаете ресурс). Здесь Вам надо быть уверенным, что блокировка сброшена (ресурс освобождён), даже если выполнение прерывается. С этой целью используется try/finally.

Совместимые библиотеки [ править | править код ]

Система программирования пользовательских интерфейсов (GUI — Graphic User Interface) системы Visual Prolog является высокоуровневой абстракцией к функциям операционной системы.

В систему включен также интерфейс с базами данных типа SQL. Почти все типы баз данных доступны с использованием Windows ODBC интерфейса. Поддерживаются также обращения к базам данных Oracle.

В инсталляционный пакет входит 50 классов (Prolog Foundation Classes). Среди них есть GDI+, криптографический, компрессия данных, COM, интерпретатор Классического Пролога PIE (Prolog Inference Engine) и пр.

Пример Ханоя

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

class hanoi 
   predicates 
       hanoi  (unsigned N). 
end class hanoi 
 
implement hanoi 
   domains 
       pole = left; center; right. 
 
   clauses 
       hanoi(N) :- move(N, left, center, right). 
 
   class predicates 
       move  (unsigned N, pole A, pole B, pole C). 
   clauses 
       move(, _, _, _) :- !. 
       move(N, A, B, C) :- 
           move(N-1, A, C, B), 
           stdiowritef("move a disc from % pole to the % pole\n", A, C), 
           move(N-1, B, A, C). 
end implement hanoi 
 
goal 
   consoleinit(), 
   hanoihanoi(4).

Функции программы Пролог

Программа Пролог для СПТ и СПГ обеспечивает съем показаний с приборов:

  • поддержку всех моделей приборов СПТ940, СПТ941, СПТ942, СПТ943, СПТ944, СПТ961, СПТ962, СПТ963, СПТ961М, СПГ741, СПГ742, СПГ761, СПГ762, СПГ763;
  • загрузку данных из накопителя АДС90;
  • загрузку данных из накопителя АДС91;
  • загрузку данных, полученных посредством программы НАКОПИТЕЛЬ;
  • загрузку данных из приборов учета при непосредственном подключении;
  • загрузку данных из приборов учета при соединении по телефонной линии посредством модема в ручном режиме или по расписанию;
  • загрузку данных из приборов учета при соединении через локальную/глобальную вычислительную сеть;
  • загрузку данных из приборов, находящихся в сети приборов;
  • ведение архива абонентов, узлов и данных учета;
  • получение текущих данных с приборов и вывод их на экран компьютера в режиме реального времени
  • вывод отчетов о потреблении энергоносителей на печать по шаблонам;
  • экспорт данных учета в таблицы EXCEL, CSV, SQL, текстовые документы (в форматах rtf, txt, dbf) и на веб-страницы.

Объектная модель

Основными элементами объектной модели VIP являются объекты, объектные типы и классы.

Основными средствами при работе с ними являются интерфейсы (interfaces), объявления классов(class declarations) и исполнения (implementations).

Интерфейсом называется именованный набор объявлений предикатов и оформленный в виде раздела interface. Интерфейсы описывают доступ к объектам извне объекта. Интерфейсы представляют собой объектные типы.

Рассмотрим следующее определение интерфейса:

interface person
predicates
  getName  () -> string Name.
  setName  (string Name).
end interface person

Это определение интерфейса с именем person. В этом примере объекты типа person имеют два предиката getName и setName, которые объявляются в этом разделе.

Интерфейсы только определяют типы объектов, классы порождают объекты. Класс имеет раздел class объявления (declaration) и раздел implement исполнения. Класс, который порождает объект person, можно объявить так:

class person  person
constructors
  new  (string Name).
end class person

Это объявление класса с именем person, который создает объект типа person. Класс имеет конструктор (contructor) с именем new, который при вызове и порождает объект типа person, передавая при этом новому объекту строку с именем Name.
У класса должен быть раздел исполнения (implement), который может выглядеть так:

implement person
facts
  name  string.
clauses
  new(Name) :- 
    name := Name.
clauses
  getName() = name.
clauses
  setName(Name) :- 
    name := Name.
end implement person

Как видно, в этом разделе должны присутствовать определения для каждого из видимых извне (public) предикатов и конструкторов, т.е. для new, getName и setName. В разделе implement можно, кроме того, объявить и определить дополнительные локальные элементы, доступ к которым возможен только из самого раздела implement. Так, класс содержит объявление факта-переменной name, который будет использоваться для хранения имени персоны.

Каждый из объектов при создании получает свою собственную реализацию факта-переменной. Выше приведенные клозы будут ссылаться только на конкретную реализацию факта-переменной внутри объекта. Мы говорим, что этот предикат является объектным предикатом (object predicate), а факт является объектным фактом (object fact).

Сохранение программного файла Turbo Prolog (Турбо-Пролог)

Для того чтобы записать на диск программу и таким образом сохранить ее, необходимо выйти из редактора нажав клавишу Esc и нажать последовательно Alt+F и потом клавишу S. В результате этих действий на экране возникнет небольшое окно, в котором будет высвечено либо заданное по умолчанию имя файла (как, например, WORK.PRO). Имя файла можно оставить без изменений, а можно и отредактировать. Если на диске уже есть файл с указанным именем (более ранняя версия редактируемой программы или какая-либо иная программа), то в результате операции записи на диск расширение имени этого файла будет сменено на .BAK, чтобы пометить старый вариант файла. Не забывайте сохранять отредактированный файл перед тем, как окончить сеанс работы с Turbo Prolog (Турбо-Пролог). В противном случае модифицированный вариант программы будет утерян.

Достаточно частое сохранение рабочего файла на диск очень полезно. В случае отказа электропитания, или программного сбоя компьютера вы всегда будете иметь достаточно «свежий» вариант программы. Некоторые программисты записывают очередные версии программы под разными именами. Генерация таких многочисленных «поколений» программных файлов может также быть полезной, так как позволяет проследить все этапы развития программы.

Modifying the Toolbar

The toolbar of the application is another useful GUI component. Usually, it would contain buttons representing some of the functions of various menu items. In short, those buttons act as short cuts to the menu. We shall now go about editing the program’s toolbar. A default toolbar is created for the program by the Visual Prolog IDE when you first create the project. From the Project Tree, double-click on the ProjectToolbar.tb.

This will invoke the toolbar editor. Note that the top portion represents the toolbar that you are editing and the bottom portion indicates the various controls that are available for you to edit those toolbar components.

In the toolbar, you would notice a set of buttons with predefined iconic images (as commonly accepted in GUI programs) If so desired, you can change those iconic images too but in this tutorial we shall not get into that fine detail. It should be indicated here that the Visual Prolog IDE does contain a nifty little icon editing program right inside it. For larger images, the IDE opens MS Paint for editing.

The buttons have been mapped out to a set of menu-item functions. But as we have now edited the menu items, we shall also edit the toolbar buttons and map it to the correct locations.

Firstly, we need to remove the buttons representing cut, copy and paste as our program does not have those capabilities. Hence select those buttons and delete them from the toolbar. After deletion the toolbar should look as follows:

We shall now map the Undo, Redo and the Help buttons to represent the following menu items: Query -> Father…, Query -> Grandfather… and Query -> Ancestor of …
(As noted before, we would not be changing the images of those buttons in this tutorial.)

Double click on the Undo toolbar button and in the Button Attributes dialog that is presented, change the Constant that internally represents the toolbar button from id_edit_undo to id_query_father.

In the same dialog box, you should change the Status Text from:

Undo;Undo

to

Query fathers;List of all fathers listed in the database

The semicolon in the above string breaks up the string into two parts. The first part is displayed as a tool-tip on the button itself and the second one will appear in the status-line of the main window.

In a similar fashion; change the Redo button’s constant so that it is now having the value of id_query_grandfather. And the Help button’s constant should get the value of id_query_ancestor_of. The status-line of these two buttons also should be suitably modified.

Starting a GUI Project

Let us start at the very beginning (a very good place to start!). When we create the project in the Visual Prolog IDE, make sure that the Project Kind is set to GUI application in MDI mode.

The IDE then creates the initial set of modules required to handle the GUI along with the GUI component resources: the main menu, one top toolbar, one bottom status bar, the About dialog and the main Task Window of the program.

Just after you create a project in this fashion, you can immediately compile it to get an empty GUI program. At this stage, the program actually would not do anything. However, it will have all the basic functionality expected in a GUI program. Visual Prolog has simply constructed the essential skeleton of a working GUI program and has provided some features commonly required.

For example; within the main window (known here as the Task Window) of the application Visual Prolog gives another window titled Messages. This window is used internally to act as the console. When the programmer uses the stdio::write(…) predicate in the program, the output would get directed to this Messages window. If Visual Prolog has not redirected the output of PFC class stdio to the Messages window, those strings would not be seen, as a GUI environment does not have a console area by default.

In a console application, the console is always available as a blackboard onto which the programmer can deposit output. That is why those applications are known as console applications. We saw that in an earlier tutorial that we could simply write to the console in such an application using stdio::write(…) predicate.

When you run our compiled GUI program at this stage, you would notice that you can flip through the menus, re-size the outer main window (or Task Window) of the program, double click on the Messages window to zoom it full extents within the Task Window, etc. Visual Prolog even gives a small pop-up menu for the Messages window which is often convenient. Right click anywhere inside the Messages window, and a small menu would open up with which you can clear the contents of the Messages window and do other activities.

But at this point this simple GUI program does not have any logical functionality that we desire. We need to do some further work to achieve this functionality.

Before we embark on populating the project with the actual working logic of the program, we shall create and/or modify some GUI components that we need. Under normal circumstances, it is here where the programmer would have to spend some time thinking out a strategy for the GUI of the program. A clear list of GUI components would have to be made, and only then one should embark on the creation and/or modification of the components. This activity should not be carried out in an unplanned manner. But for the sake of simplicity, we shall proceed in this tutorial with the assumption that this planning process is over.

All GUI components are stored as separate resource files during the coding phase. In most other programming languages; these resource files are separately compiled and then included into the main code during the linking process. Visual Prolog deals with all this resource compilation and linkage issues automatically without unnecessarily bothering the user.

Side Effects

Besides a strict evaluation order Prolog also has side effects.
For example Prolog has a number of predefined predicates for reading and writing.

The following goal will write the found ancestors of «Pam»:

?- ancestor("Pam", AA), write("Ancestor of Pam : ", AA), nl().

The ancestor call will find an ancestor of «Pam» in AA.

The write call will write the string literal «Ancestor of Pam : «, and then it will write the value of AA.

The nl call will shift to a new line in the output.

When running programs in PIE, PIE itself writes solutions, so the overall effect is that your output and PIE’s own output will be mixed.
This might of course not be desirable.

A very simple way to avoid PIE’s own output is to make sure that the goal has no solutions.
Consider the following goal:

?- ancestor("Pam", AA), write("Ancestor of Pam : ", AA), nl(), fail.

fail is a predefined call that always fails (i.e. it has no solutions).

The first three predicate calls have exactly the same effect as above: an ancestor is found (if such one exists, of course) and then it is written.
But then we call fail this will of course fail. Therefore we must pursuit a backtrack point if we have any.

When pursuing this backtrack point, we will find another ancestor (if such one exists) and write that, and then we will fail again.
And so forth.

So, we will find and write all ancestors. and eventually there will be no more backtrack points, and then the complete goal will fail.

There are a few important points to notice here:

  • The goal itself did not have a single solution, but nevertheless all the solutions we wanted was given as side effects.
  • Side effects in failing computations are not undone.

These points are two sides of the same thing.
But they represent different level of optimism.
The first optimistically states some possibilities that you can use, while the second is more pessimistic and states that you should be aware about using side effects, because they are not undone even if the current goal does not lead to any solution.

Anybody, who learns Prolog, will sooner or later experience unexpected output coming from failing parts of the program.
Perhaps, this little advice can help you: Separate the «calculating» code from the code that performs input/output.

In our examples above all the stated predicate are «calculating» predicates.
They all calculate some family relation.
If you need to write out, for example, «parents», create a separate predicate for writing parents and let that predicate call the «calculating» parent predicate.

Теоретические сведения о Prolog

Prolog (Programming in logic) — это язык высокого уровня, не алгоритмический, предназначенный для написания программ с использованием концепций и методов логического программирования.

История

Пролог был разработан в Марсельском университете во Франции Алэном Колмероэ и другими членами «группы искусственного интеллекта» в 1973 году. Данная команда энтузиастов разработала программу, предназначенную для доказательства теорем. Написана она была на Фортране, и использовалась при построении систем обработки текстов на естественном языке. Работала программа довольно медленно и назвалась Prolog (от Programmation en Logique на франц.). Программа послужила прообразом Пролога.

Язык логического программирования prolog — декларативный, что означает, что программа, написанная на нем, выглядит как набор логических описаний, определяющих цель, ради которой она и написана.

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

Логика предикатов — это простейший способ объяснить, как «работает» мышление.

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

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

Области применения языка Prolog и декларативных языков в целом

  • Реализация систем искусственного интеллекта.
  • Создание экспертных систем и оболочек экспертных систем.
  • Разработка систем помощи принятия решений.
  • Разработка систем обработки естественного языка.
  • Построение планов действий роботов.
  • и т.п.

Особенности языка

  • Описание проблемы и правил ее решения.
  • Нахождение всех возможных решений с помощью механизма поиска с возвратом (backtracking).
  • Легкий синтаксис.

Как установить программу Пролог

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

Установка программы ПРОЛОГ:

  1. Закройте все работающие приложения

Вставьте диск или флэш-накопитель, содержащий дистрибутив программы, в устройство для чтения компакт-дисков на компьютере

Откройте содержимое установленного компакт-диска или папки, где содержится дистрибутив программы

Дважды щелкните на исполняемом файле prolog_95_ХХХХХХХХ.exe

Следуйте инструкциям программы установки, чтобы установить ПРОЛОГ в вашей системе

Перезагрузите компьютер

Компоненты программы ПРОЛОГ образуют одноименную группу в разделе Программы — Логика меню панели задач. Ярлык для запуска программы также создается на рабочем столе.

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

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

Что такое Список?

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

Список, содержащий числа 1, 2 и 3 записывается как

 1, 2, 3 

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

  • Число «1» является первым элементом,
  • «2» — второй,
  • «3» — третий.

Список и список различны.

Каждый компонент списка называется элемент (element). Для того, чтобы сформировать списковую структуру данных, следует разделять элементы запятыми и заключать их всех в квадратные скобки. Посмотрим на некоторые примеры:

"dog", "cat", "canary"
"valerie ann", "jennifer caitlin", "benjamin thomas"

Один и тот же элемент может быть представлен в списке несколько раз, например:

 1, 2, 1, 3, 1 

Объявление Списков

Для объявления домена — списка целых используется декларация домена, как показано ниже:

domains
  integer_list = integer*.

Звездочка означает «список этого»; то есть, integer* означает «список целых».

Обратите внимание на то, что слово «list» не имеет специального значения в Visual Prolog. Вы равным образом могли бы назвать Ваш списковый домен как zanzibar

Именно звездочка, а не имя, предписывает этому домену быть списком.

Элементами в списке может быть что угодно, включая другие списки. Но все элементы в списке должны принадлежать одному домену, и дополнительно к декларации спискового домена должна быть декларация domains для элементов:

domains
  element_list = elements*.
  elements = ....

Здесь elements должны быть приравнены к простым доменным типам (например, integer, real или symbol) или к набору возможных альтернатив, обозначенных различными функторами. Visual Prolog не допускает смешивание стандартных типов в списке. Например, следующие декларации ошибочно представляют списки, созданные из integers, reals и symbols:

element_list = elements*.
elements =
    integer;
    real;
    symbol.
        /* Неправильно */

Выходом для объявления списков из integer, real и symbols является объявление домена общего для всех типов, где функтор показывает какому типу принадлежит тот или иной элемент. Например:

element_list = elements*.
elements =
    i(integer);
    r(real);
    s(symbol).
        /* функторами являются i, r и s */

(Подробнее об этом — в этом же руководстве в разделе «Составные списки»).

Головы и Хвосты

Список на самом деле является рекурсивным составным объетом. Он состоит из двух частей — головы списка, которым является первый элемент, и хвоста — списка, который включает все следующие элементы.

Хвост списка всегда есть список; голова списка есть элемент.

Например,

голова списка a, b, c есть a
хвост списка a, b, c есть b, c

Что происходит, когда мы имеем дело со списком, содержащим один элемент? Ответом является:

головой списка c является c
хвостом списка c является 

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

Пустой список не может быть разбит на голову и хвост.

Это означает, что, концептуально говоря, списки имеют древовидную структуру подобно другим составным объектам. Древовидная структура списка есть:

    list
   /    \
  a    list
      /    \
     b    list
         /    \
        c    list
            /    \
           d      []

Более того, одноэлементный список, такой как — это не тот же самый элемент, который этот список содержит, поскольку является действительно составной структурой данных, как это видно здесь:

    list
   /    \
  a     []

Преимущества и недостатки Prolog

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

Список задач, в которых Пролог удобен:

  • Искусственный интеллект

  • Компьютерная лингвистика. Написание стихов, анализ речи

  • Поиск пути в графе. Работа с графами

  • Логические задачи

  • Нечисловое программирование

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

Иллюстрация к задаче

Пролог такой замечательный язык! Но почему его крайне редко используют?Я вижу две причины:

  1. Производительность

  2. Альтернативы (например, нейросетей на Python)

Пролог решает задачи методом полного перебора. Следовательно, его сложность растет как O(n!). Конечно, можно использовать отсечения, например, с помощью «!». Но все равно сложность останется факториальной. Простые задачи не так интересны, а сложные лучше реализовать жадным алгоритмом на императивном языке.

Области, для которых предназначен Пролог, могут также успешно решаться с помощью Python, C/C++, C#, Java, нейросетей. Например, сочинение стихов, анализ речи, поиск пути в графе и так далее.

Я не могу сказать, что логическое программирование не нужно. Оно действительно развивает логическое мышление. Элементы логического программирования можно встретить на практике. И в принципе, логическое программирование — интересная парадагима, которую полезно знать, например, специалистам ИИ.

Типы и потоки ввода-вывода

По умолчанию предикаты имеют тип procedure (процедуры). Не стоит писать квалификатор procedure до тех пор, пока в этом не возникнет необходимость (но, возможно, в этом случае следует рассмотреть необходимость изменения имени предиката).

predicates
  doSomeThing  ().  % не пишите здесь "procedure"

По умолчанию все аргументы предикатов являются входными. Неиспользуемые комбинации потоков ввода-вывода писать не следует.

predicates
  doSomeThing  (string In1, string In2).
  % не пишите здесь потоки ввода-вывода, если все потоки являются и так входными

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

predicates
  doSomeThing  (string In1 /* не писать здесь */, string Out2 out).

Если придикат имеет только один вариант потоков входа-выхода, надо использовать вместо шаблона.

predicates
  doSomeThing  (string In1 /* не писать здесь */, string Out2 out).
  % не писать шаболоны ввода-вывода, если вариант всего один

По умолчанию факты являются недетерминированными — nondeterm. Не следует писать nondeterm, если в этом нет особой необходимости (но следует, возможно, рассмотреть изменение имени факта).

facts
  personData_fact  (string FirstName, string LastName, string Address). 
  % не писать здесь "nondeterm"
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector