Программа пролог логика

SWI-Prolog native development tools

Built-in tools

The built-in tools provide a feature rich environment for developing with
SWI-Prolog. The tools are built on top of the portable XPCE graphics
system. They look outdated and the learning curve for the built-in Emacs
clone is steep. The real-time semantic highlighting greatly reduces the
number of bugs you need to fix after writing your program and the
context menu on predicates and goals make it easy to navigate your code.

  • PceEmacs is a GNU-Emacs clone in XPCE/Prolog, providing
    Prolog syntax highlighting based on parsing and
    cross-referencing the editor buffer. Colouring highlights variables,
    quoted entities, comments, goals (classified as
    built-in, imported, local, dynamic and undefined), predicates
    (classified as local, public and unreferenced), and file references
    (classified as existend/non-existend). PceEmacs is started using
    the predicates emacs/0, edit/0 or edit/1.
  • The graphical tracer provides source-level
    debugging, using three views: your source, variable bindings, and
    the stack. The stack view includes choicepoints and visualises
    the effect of executing the cut!
  • The Execution Profiler provides a graphical
    overview of call and time statistics.
  • The Cross Referencer analyzes dependencies in
    the loaded program and points out undefined and unused code. It
    can also generate module headers and import directives based on
    the analysis.
  • The Prolog Navigator provides an
    explorer-like view on a directory holding Prolog source files.
    Sources files can be expanded in the tree to show predicates,
    exports, XPCE classes and methods. Can be used to edit entities
    or enable debugging them (spy).

Both the Windows Prolog console swipl-win.exe and the app for MacOSX
(swipl-win) provides a menu to access many of these facilities

We intend to allow the user to select preferred tools and combine them
with whatever they like. In other words, we don’t want to force the user into
using a bulky all-in-one closed toolkit.

SWISH (web based Prolog)

SWISH provides a web-based tool for
running Prolog. It provides a CodeMirror
based editor with server-enriched semantic highlighting based on the
same library as the above mentioned built-in editor. SWISH can display
Prolog results as tables, charts and anything supported by HTML5 and
JavaScript. SWISH notebooks provide functionality inspired by
Jupyter/IPython notebook.

SWISH provides a smooth transition starting with conventional Prolog
programs using text output. Next, HTML5 output can be added. Workflows,
tutorials, etc. can be written as notebooks that mix text, queries and
program fragments as well as embedded web applications that provide a
rich experience to non-programmers.

SWISH can run in several configurations.

  • As a public server it can be used to run harmless queries against
    a Prolog itself or a read-only database.
  • It can be installed with authentication enabled, which allows
    for running arbitrary Prolog programs.
  • Mixed, where non-authenticated users can run harmless queries and
    authenticated users can run anything.

SWI-Prolog Editor (Windows)

Gerhard Röhner has developed an integrated Prolog editor in
MS-Windows following the conventions of this platform. The embedded
SWI-Prolog provides functionality similar to swipl-win.exe,
including the possibility to run XPCE GUI programs.

Especially for classroom usage on MS-Windows, you should consider this
version. The site also contains some demo material.

PIE: Prolog Inference Engine

Before we start you should install and build the PIE example.

  • Select «Install Examples» in the Windows start menu (Start -> Visual Prolog -> Install Examples).
  • Open the PIE project in the VDE and run the program, as it is described in <a href=»../tut01/default.htm»>Tutorial 01: Environment Overview</a>.

When the program starts it will look like this:

Select File -> New and enter the father and grandFather clauses above:

While the editor window is active choose Engine -> Reconsult.
This will load the file into the engine.
In the Dialog window you should receive a message like this:

Reconsulted from: ....\pie\Exe\FILE4.PRO

Reconsult loads whatever is in the editor, without saving the contents to the file, if you want to save the contents use File -> Save.

File -> Consult will load the disc contents of the file regardless of whether the file is opened for editing or not.

Once you have «consulted» the theory, you can use it to answer goals.

On a blank line in the Dialog window type a goal (without the ?- in front).

For example:

When the caret is placed at the end of the line, press the Enter key on your keyboard.
PIE will now consider the text from the beginning of the line to the caret as a goal to execute.
You should see a result like this:

Recursion Using Functors

When data is described using functors, it can be treated like any other piece of data. For example, you can write a predicate that can be made to recursively search through data which used compound domains using functors.

Let us get back briefly to the ancestor predicate, which we had used in the first part of the tutorial.

In order to determine if somebody is an ancestor of someone else, we used a recursive definition for the predicate, i.e. a definition that is defined in terms of itself. like this:

ancestor(Person, Ancestor) :- parent(Person, Ancestor).
ancestor(Person, Ancestor) :- parent(Person, P1), ancestor(P1, Ancestor).

This declaration states that a parent is an ancestor, and that an ancestor to a parent is also an ancestor. If you examine the variables in the above definition, it can very well stand for either simple domains or compound domains.

Let us define the data thus:

parent(person("Bill", "male"), person("John", "male")).
parent(person("pam", "female"), person("Bill", "male")).

If we now ask PIE to solve the following goal,

P=person("pam", "female"), ancestor(P, Who)

…this is what we will get:

The PIE engine has recursively examined the parent facts to reveal the two possible solutions to the answer. By the way, in the above query, you would also notice that we have bound a variable P to the person compound domain when specifying the goal to PIE. This was done to make the code more readable but it also demonstrates the fact that we can bind a piece of data specified as a compound domain into any Prolog variable.


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

Нет смысла вдаваться в подробности отладки до тех пор, пока Вы не освоимли язык программирования системы Visual Prolog. Одноко краткое объяснение будет полезно, поскольку это даст возможность понимания и экспериментирования с языком.

Для запуска отладчика выберите Debug -> Run (Отладка -> Пуск) в меню. Если исполняемый файл проекта не соответсвует исходным текстам, то проект сначала будет перестроен, после чего начнется сессия отладки.

Обратите внимание — Вы всегда можете остановить отладку путем выбора Debug -> Stop Debugging (Отладка -> стоп отладки) в меню.

Когде отладка начинается, IDE прежде всего загружает отладочную информацию и только потом приступает к запуску программы. Действия IDE приостанавливаются непосредственно перед началом исполнения раздела goal. Для указания на это открывается текстовый редактор и указатель устанавливается на ключевое слово goal:

Вы можете вызывать выполнение программой одиночных шагов используя команды Step Into (Шаг внутрь) и Step Over (Шаг Поверх) в меню Debug (Отладка).

Попробуйте Step Into (Шаг внутрь): это окрывает другое окно редактора с кодом mainExe::run, а указатель устанавливается на начале этого кода.

Через меню View (Просмотр) Вы можете открывать различные окна отладчика, которые мы кратко поясним.

Окно Run Stack (Стек исполнения):

содержит «picture» (картину) стека исполнения. Точнее говоря то, что Вы видите, зависит от установок в панели Tools -> Options… -> Debugger (Инструменты -> Опции … -> Отладчик). В целом, стек исполнения содержит набор строк, соответствующих вызовам, которые были сделаны. Однако, следует иметь в виду, что внутренние меры оптимизации, предпринятые компилятором на этапе компиляции (так называемые оптимизации последнего вызова) могут удалить некоторые вызовы.

Стек исполнения (The run stack) не только показывает Вызовы, но и показывает точки нейтрализации исключений (trap points) и точки перебора (backtrack points), это объясняется в других руководствах, гда мы объясняем окно со стеком вызовов более детально.

Окно Local Variables (Локальные переменные):

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

Окно Facts (Факты):

Содержит данные о глобальном состоянии программы. Это состояние сохраняется в базе фактов. Fact databases (Базы данных фактов) являются уникальным свойством системы Visual Prolog, которое будет пояснено в другом руководстве. Вы можете добавлять объекты из окна Local Variables (Локальные Переменные) в окно Facts (Факты), и, таким образом, контролировать изменение состояний интересующих Вас объектов.

Окно Breakpoints (Точки Останова):

показывает текущие точки остнова программы (Мы установили одну точку, чтобы окно не было бы пустым). Вы можете установить/удалить точки останова с помощью меню Debug -> Toggle Breakpoint (Отладчик -> Сброс точек останова).

Остальные окна отладчика предназначены для низкоуровневой отладки и здесь не рассматриваются.

Аргументы множественных типов

Для того, чтобы предикат в Visual Prolog допускал использование аргументов различного типа, необходимо использовать функторные объявления. Следующий пример, клауза your_age clause будет воспринимать аргументы типа age, которые могут иметь тип string, real или integer.

    age = i(integer); r(real); s(string).
class predicates
    your_age (age).
    your_age(i(Age)) :- stdio::write(Age).
    your_age(r(Age)) :- stdio::write(Age).
    your_age(s(Age)) :- stdio::write(Age).

При этом Visual Prolog не допускает декларации вида:

/* Не допустимо. */
    age = integer; real; string.

Глава 3. Основы пролога 44

в ЛОГике 44

Факты и Правила. 45

То что известно 45

То что вы можете получить из заданных
фактов 46

Запросы 46

задание фактов, правил и запросов 48

основные положения 49

Выводы 50

Упражнения 51

естественного языка в программы на
Прологе 51

(факты и правила) 51

о фактах 51

о правилах 52

правил 52

Упражнения 54

(связи) 54

(обобщенные предложения) 55

переменные получают свои значения 55

переменные 57

(запросы) 58

цели: Конъюнкция и Дизъюнкция 59

Комментарии 60

такое Сопоставление? 61

Выводы 62


Для применения класса user, можно использовать свойства одного из наших классов person. Класс user похож на класс person, за исключением того, что user имеет дело еще и с паролями. Хотелось бы, чтобы наш класс user наследовал раздел implement из класса person. Это можно сделать с помощью квалификации inherits, как показано ниже:

implement user
    inherits person
    password  string.
    new(Name, Password) :-
        password := Password.
    trySetPassword(Old, New, Confirm) :-
        New = Confirm,
        password := New.
    validatePassword(Password) :-
        password = Password.
end implement user

Раздел implement подтверждает, что этот класс наследует (inherits) свойства класса person. Отсюда следует, что:

  • Объект person встраивается в каждый созданный объект user.
  • Все предикаты, объявленные в интерфейсе person, могут быть наследованы из класса person в класс user.

Когда наследуется какой-нибудь предикат, определять его в разделе implement не нужно, т.к. наследуется определение предиката из раздела implement наследуемого класса.

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

implement user
  person  person.
  password  string.
  new(Name, Password) :-
    person := person::new(Name),
    password := Password.
  getName() = persongetName().
  setName(Name) :- 
end implement user

Действие этого кода похоже на действие предыдущего фрагмента, но размер текста увеличился.
В этом фрагменте наследования из класса person не происходит. Вместо этого создан объект person и он сохранен в одноименном факте-переменной. Вместо наследования кода getName и setName они просто переопределены и теперь обращаются за решением к объекту из факт-переменной. Такие обращения за решением можно сократить с помощью ключевого слова delegate. Код в этом случае сократится.

implement user
  delegate interface person to person
  person  person:=erroneous.
  password  string.
  new(Name, Password) :-
    person := person::new(Name),
    password := Password.
end implement user_class

Функционирование то же, но:

  • Вызовы предикатов, относящихся к объекту person транзитом передаются в него
  • Mожно динамически изменить значение в факт-переменной на другой объект, например, на объект класса personInDB простым присваиванием нового объекта факту-переменной.

VIP обрабатывает такие непрямые обращения довольно эффективно, но в случае наследования обработка все же происходит гораздо быстрее.

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

Создание и доступ

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

  P = person::new("John"),
  Name = PgetName(),

В первой строке происходит вызов конструктора (constructor) new класса person. Созданный объект запоминается в переменной P.

Во второй строке, переменной Name присваивается результат исполнения объектного предиката getName объекта P.

В последней строке происходит вызов предикат write класса io с передачей ему имени Name.

Отметим, что на имена классов ссылаются с помощью символа ‘::’, например, person::new(…). А объектные предикаты ссылаются на объекты с использованием символа ‘:’, напрмер, P:getName.
Наконец, отметим, что конструкторы являются функциями, которые возвращают объекты, даже если эти конструкторы не объявлены, как функции. Тип возвращаемого значения определяется исходя из объявления класса, к которому применяется конструктор.

Support in standard editors

The lack of keywords, existence of dynamic operator declarations (see
op/3), macro expansion and meta-calling make Prolog a difficult language
for generic editors and IDEs. On the other hand, switching between
editors is hard and thus most people like using one editor for all their
tasks. Below are plugins for generic editors that we are aware of.
Please let us know if you know other plugins.

Using GNU-Emacs

Unfortunately, standard GNU-Emacs Prolog mode is very weak, especially at
handling proper Prolog indentation. The good news is that there is a better
mode today. For more information, see the FAQ.

Eclipse based

Prolog Development Tool — PDT
The PDT is a Prolog IDE provided as a plug-in for the Eclipse
Platform. All PDT features are implemented for SWI-Prolog, most also for
Logtalk). All native SWI-Prolog development tools (graphical tracer /
debugger, profiler, …) can be used within the PDT.
Prolog Development Tools — ProDT
Prolog Development Tools (ProDT) is a Prolog Integrated Development
Environment (IDE) aiming to be as rich in functionality as the Eclipse’s
java IDE, giving the developer a single environment where it can control
the development of a Prolog project from code edition, test execution,
debugging, and more…

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:



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.

Файлы и папки Turbo Prolog (Турбо-Пролог)

  • PROLOG.EXE — основной файл системы Турбо-Пролог.
  • PROLOG.OVL — оверлейный файл, используемый системой при запуске, при создании .EXE файлов и при выполнении некоторых других функций.
  • PROLOG.SYS — файл, содержащий информацию о цвете, расположении окон системы, также как и информацию об использумых системой директориях.
  • PROLOG.ERR — файл с сообщениями об ошибках.
  • PROLOG.HLP — файл с текстом применяемых в системе подсказок (обращение к нему осуществляется при помощи функциональной клавиши F1).
  • GEOBASE.PRO и GEOBASE.INC — демонстрационная программа базы данных по географии США GeoBASE.
  • GEOBASE.DBA — данные для программы GeoBase.
  • GEOBASE.HLP — текст подсказок программы GeoBase.
  • PROLOG.LIB и INIT.OBJ — файлы, используемые системой Турбо-Пролог при создании выполнимых файлов.
  • EXAMPLES — директория, содержащая программы, используемые в разделе обучения Руководства пользователя.
  • ANSWERS — директория, содержащая ответы на упражнения из Руководства.
  • PROGRAMS — директория, содержащая демонстрационные программы.
  • PRO — директория файлов исходных текстов программ.
  • OBJ — директория объектных файлов.
  • EXE — директории выполнимых файлов.

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

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

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

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

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

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

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

Understanding What we have Done So Far

Let us now pause our tutorial and take a breather (phew!). «Where is the encapsulation?», — you should ask. Well, we have broken up the code into two parts. There is the non-interactive logical core which we took care of earlier. But those parts which requires inputs from the user, has been squirrelled away in separate portions into different event handlers. As far as the rest of the program is concerned, it need not be even aware where those event handlers are actually written in the program. Now, let us insert some more interactive code into yet another event handler.

For the Query|Ancestor of … menu item, add the following clause body before the default clause body inserted automatically by Visual Prolog:

    onQueryAncestorOf  window::menuItemListener.
    onQueryAncestorOf(_Source, _MenuTag) :-
     X = ancestorDialog::tryGetName(This),
          stdIO::writef("\nancestor of % test\n", X),
          ancestor(X, Y),
          stdIO::writef("% is the ancestor of %\n", Y, X),
    onQueryAncestorOf(_Source, _MenuTag).

The strategy for the above code is to acquire a string from a modal dialog box presented by the ancestorDialog which we had created earlier. The above predicate assumes that there is a globally accessible predicate called tryGetName available in the ancestorDialog module which will return the name of the person whose ancestors we are seeking.

As was seen in the onFileOpen Event Handler, we had sought a string (the filename) returned from a modal dialog. The modal dialog itself was invoked by the predicate vpiCommonDialogs::getFileName(…) It is the same strategy that we are adopting for obtaining a string from the ancestorDialog. The only difference is that vpiCommonDialogs::getFileName(…) gave a built-in standard Windows modal file dialog. But for our home grown ancestorDialog, we would have to do some more coding as we shall shortly see.

On compiling the program, there will be one error:

error c229: Undeclared identifier 'ancestorDialog::tryGetName/1->'

The reason for this error is because the onQueryAncestorOf predicate is expecting this globally accessible predicate called tryGetName from the module ancestorDialog.pro. But we haven’t written that yet! Let us now get down to rectifying that error.

This predicate is defined within one module, but called from another module. Hence we need to ensure that the declaration is kept not in the .pro l parts of the program. The class declaration file of a module (extension .cl) is one such place. Therefore, let us now open ancestorDialog.cl and insert the following piece of code. (It is a declaration statin called tryGetName is implemented within the module, and that predicate can be called from other modules too.)

    trygetName  (window Parent) -> string Name determ.

In ancestorDialog.pro, let us now insert the core logic relevant to that module. Just the way we did for Taskwindow.pro, it is inserted just after the following lines:

implement ancestorDialog inherits dialog
    open core, vpiDomains

Here is the code to be inserted:

    optionalString = none(); one(string Value).
class facts
    name  optionalString := none().
    tryGetName(Parent) = Name :-
        name := none(),
        _ = ancestorDialog::display(Parent),
        one(Name) = name.

Now there is one last issue which is remaining. We need to change the event handler for the OK button. This is required, so that the dialog would assert the value entered by the user into the name class facts. If that is not done, then the above predicate will find an empty string.

The default code given by Visual Prolog is shown below:

    onOkClick  button::clickResponder.
    onOkClick(_Source) = button::defaultAction.

The above code now will have to be changed into the following:

    onOkClick  button::clickResponder.
    onOkClick(_Source) = button::defaultAction :-
        Name = idc_ancestordialog_personnamegetText(),
        name := one(Name).

Now we have finally finished our program. If you now compile and run the program, you should not get any errors.

Integrated Development Environment (IDE)

Visual Prolog Integrated Development Environment (IDE)  is designed
to make it easy, convenient and fast to develop, test, and modify applications
written in Visual Prolog.

It might be especially useful in developing of large projects.

  • Tree representation of modules, include files, and resources in
    the Project window helps to group project
    items into packages and thus gives an extra level of abstraction.
  • The Text Editor supports convenient
    text editing and browsing to declarations and implementations.
  • The Dialog Editor provides standard
    controls to design dialogs.
  • The Menu Editor allows to create both
    pull-down and pop-up menus.
  • The Toolbar Editor allows to create
    various kinds of toolbars.
  • The Graphics Editor is a convenient
    tool for creating, viewing and editing icons, cursors and small bitmaps.
  • The Build Facility supports inserting
    of necessary packages and include directives.
  • The Browse Facilities supports search for specific entities, «go
    to definition» and «go to declaration»

Please see
Environment Overview for detailed information and screenshots.

Оцените статью
Рейтинг автора
Материал подготовил
Андрей Измаилов
Наш эксперт
Написано статей
Добавить комментарий