В языке Visual Prolog используются следующие разделы программы:
• (class) facts – объявление предикатов, описывающих факты (а также внутренних баз данных и фактов-переменных);
• (class) predicates – объявление предикатов (служит для описания используемых программой предикатов, этот раздел является обязательным);
• domains – определение типов данных (содержит определения доменов, которые описывают различные типы объектов, используемых в программе, если используются стандартные типы, то раздел может не использоваться);
• constants – объявление констант;
• clauses – определение фактов или правил (в раздел заносятся факты и правила статической базы данных, которая и является собственно программой, этот раздел является обязательным);
• goal – цель программы (в разделе формулируется цель (запрос) созданной программы. Составными частями при этом могут являться некие подцели, из которых формируется единая цель программы, этот раздел является обязательным и может быть только один в проекте в файле main.pro).
Для примера рассмотрим следующий код программы:
implement main
open core, console
domains
gender = female(); male().
class facts – familyDB
person : (string Name, gender Gender).
parent : (string Person, string Parent).
class predicates
father : (string Person, string Father) nondeterm anyflow. % Отец
grandFather : (string Person, string GrandFather) nondeterm (o,o). % Дед
ancestor : (string Person, string Ancestor) nondeterm (i,o). % Предок
clauses
father(Person, Father) :- parent(Person, Father), person(Father, male()).
grandFather(Person, GrandFather) :- parent(Person, Parent), father(Parent, GrandFather).
ancestor(Person, Ancestor) :- parent(Person, Ancestor).
ancestor(Person, Ancestor) :- parent(Person, P1), ancestor(P1, Ancestor).
person("Bill", male()).
person("John", male()).
person("Pam", female()).
parent("John", "Judith").
parent("Bill", "John").
parent("Pam", "Bill").
run() :->
init(),
write("father; test"),nl,
father(X, Y),
write(Y, "is the father of", X),nl,
fail.
run() :-
nl,
write("grandFather test"),nl,
grandFather(X, Y),
write(Y, "is the GrandFather of", X),nl,
fail.
run() :-
nl,
write("ancestor of Pam test"),nl,
X = "Pam",
ancestor(X, Y),
write(Y, "is the ancestor of", X),nl,
fail.
run() :-
nl,
write("End of test"),
_=readLine().
end implement main
goal
console::run(main::run).
В данном примере используются почти все основные разделы программы.Язык Visual Prolog – типизированный, поэтому предикаты необходимо объявлять. В объявлении предиката указывается его имя, ставится знак двоеточия, а затем в круглых скобках через запятую перечисляются имена доменов (типов данных) аргументов:
class facts – familyDB
person : (string Name, gender Gender).
Словом familyDB
обозначено имя базы данных. В объявлениях предикатов можно использовать комментарии специального вида. Слова Name
и Gender
в этом объявлении обозначают комментарии. Компилятор их игнорирует. Такие комментарии пишутся в одно слово с прописной буквы.
Предикаты объявляются в разделах class facts (если определяются только в виде фактов) или class predicates, а определяются в разделе clauses. Цель программы формулируется в разделе goal, который находится в файле main.pro. Обычно в разделе goal только вызывается некоторый предикат, который используется для составления запросов. В данном примере и всюду далее таким предикатом является run
.
Раздел open имплементации класса main
следует изменить следующим образом (см. урок 1):
open core, console
Вывод решений для запроса, например для цели ?- father(X, Y)
, организуется с помощью предиката fail
. Этот предикат имеет значение ложь. Он вынуждает программу вернуться для поиска других решений.
Ключевое слово nondeterm
в объявлении предиката означает, что область истинности этого предиката может содержать более одного элемента или не содержать ни одного. Ключевое слово anyflow
означает, что некоторые аргументы предиката могут быть как входными, так и выходными. Последовательность (i,o)
– означает, что первый аргумент предиката входной, а второй – выходной, ну и последовательность (o,o)
– соответственно означает, что оба аргумента предиката – выходные, они возвращают некоторые значения.
Предикат init
инициализирует консоль.
Для ввода и вывода в консоли используются буфер ввода и буфер вывода, соответственно. Предикат clearInput
очищает буфер ввода, предикат clearOutput
очищает буфер вывода. Предикат readLine
считывает содержимое буфера ввода в строку (string
) и при этом полностью очищает содержимое этого буфера. В данном случае программа просто ожидает ввода любого символа.
Предикат должен просматривать входной список и те элементы, которые меньше n помещать в первый, которые больше – во второй