2014-02-11 1 views
4

Я пытаюсь написать предикат move/3, который обрабатывает несколько типов терминов, каждый из которых определяется в отдельном файле. Я пытаюсь использовать модули для этого, потому что файлы содержат другие предикаты, которые должны соответствовать именам соответственно.Определить части предиката на нескольких модулях

Таким образом, я создал модуль cat.prolog с содержимым:

:- module(cat, [move/3]). 
:- multifile(move/3). 

move(cat(C), P, cat(C2)) :- 
    ... 

Аналогично для dog.prolog.

И main.prolog с:

:- use_module(['cat.prolog'], [move/3]). 
:- use_module(['dog.prolog'], [move/3]). 

(various predicates that use move/3 and expecting the clauses from all imported modules to be applicable.) 

Попытка запустить это в SWI-Пролог:

?- ['main.prolog']. 
% cat.prolog compiled into cat 0.00 sec, 4,800 bytes 
ERROR: Cannot import dog:move/3 into module user: already imported from cat 
Warning: /home/edmund/main.prolog:2: 
     Goal (directive) failed: user:use_module([dog.prolog],[move/3]) 
% main.prolog compiled 0.00 sec, 10,176 bytes 
true. 

На данный момент я могу использовать dog:move/3 и cat:move/3, но не move/3. Он работает для корпуса cat, но не для корпуса dog.

У меня такое ощущение, что есть действительно очевидный способ сделать это. Я пробовал комбинировать модули и импорт и многофайловые директивы во многих отношениях, и до сих пор не нашел еще ...

+1

Вы пытались объявить, что move/3 будет многофилировать в вашем 'main' модуле? –

+1

Я попытался, но это не имело никакого значения, но ошибка об этом уже была импортирована. – Edmund

ответ

5

многофайловой/1 синтаксис прост, но documentation не хватает простой примера ...

I создано 3 modules Файлы: pets.pl, cat.pl, dog.pl.

:- module(pets, [test/0, move/3]). 
:- multifile move/3. 
move(A,B,C) :- writeln(pets-move(A,B,C)). 
test :- forall(move(A,B,C), writeln(move(A,B,C))). 

:- module(cat, []). 
:- use_module(pets). 
pets:move(A,B,C) :- writeln(cat-move(A,B,C)). 

:- module(dog, []). 
:- use_module(pets). 
pets:move(A,B,C) :- writeln(dog-move(A,B,C)). 

Примечание соответствующий синтаксис Module:Pred :- ... в «зависимых» файлов

?- [cat,dog]. 
% pets compiled into pets 0.00 sec, 3 clauses 
% cat compiled into cat 0.01 sec, 7 clauses 
% dog compiled into dog 0.00 sec, 3 clauses 
true. 

?- test. 
Correct to: "pets:test"? yes 
pets-move(_G41,_G42,_G43) 
move(_G41,_G42,_G43) 
cat-move(_G41,_G42,_G43) 
move(_G41,_G42,_G43) 
dog-move(_G41,_G42,_G43) 
move(_G41,_G42,_G43) 
true. 

?- 
+0

Спасибо, это выглядит многообещающе. Интересно, что у вас есть модули для кошки и собаки, включая модуль для домашних животных, а не наоборот, как и у меня. – Edmund

+0

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

+0

@PauloMoura: ваш комментарий попадает в суть проблемы. Есть очевидное решение, которое я пропускаю? – CapelliC

2

Альтернативным решением является определение протокола Logtalk (т.е. интерфейс) для объявления предикаты, такие как move/3, а затем определить любое число объектов, реализующих этот протокол. Вы можете запустить Logtalk, используя большинство компиляторов Prolog, включая SWI-Prolog. Например:

:- protocol(pets). 

    :- public(move/3). 
    ... 

:- end_protocol. 


:- object(cat, implements(pets)). 

    move(A, B, C) :- 
     ... 

:- end_object. 


:- object(dog, implements(pets)). 

    move(A, B, C) :- 
     ... 

:- end_object. 

Предполагая, что каждая сущность, указанная выше, определена в ее собственном файле, например. pets, cat.lgt и dog.lgt затем вы можете сделать:

$ swilgt 
... 
?- {pets, cat, dog}. 
... 
? - cat::move(A, B, C). 
... 

Logtalk поддерживает как прототип и классы/экземпляры, так что вы можете определить любой тип структуры иерархии/программы, которая подходит для вашего приложения. Это также, вероятно, более чистое решение, чем превращение предикатов множества, чтобы иметь разные реализации предикатов для разных объектов.

+0

Спасибо за ответ. Это не совсем то, что я хочу, но Logtalk звучит интересно, поэтому я прочитаю об этом. – Edmund

4

Второй рабочий раствор, на этот раз без удлинителя Logtalk на Пролог, после моего комментария об использовании include/1 директиву:

----- common.pl ----- 
:- export(move/1). 
--------------------- 

----- cat.pl ----- 
:- module(cat, []). 
:- include(common). 

move(cat). 
--------------------- 

----- dog.pl ----- 
:- module(dog, []). 
:- include(common). 

move(dog). 
--------------------- 

$ swipl 
... 
?- use_module(cat, []), use_module(dog, []). 
% cat compiled into cat 0.00 sec, 4 clauses 
% dog compiled into dog 0.00 sec, 4 clauses 
true. 

?- cat:move(X). 
X = cat. 

?- dog:move(X). 
X = dog. 

?- module_property(cat, exports(Exports)). 
Exports = [move/1]. 

?- module_property(dog, exports(Exports)). 
Exports = [move/1]. 

Как и в растворе Logtalk, Многофайловые предикаты не являются ответом.

Следует отметить, что в большинстве модулей модулей Prolog, включая SWI-Prolog, любой предикат модуля можно вызывать с использованием явной квалификации, как в запросах выше. Но использование файла для хранения общих битов имеет еще два преимущества: (1) он делает явным в одном месте общие биты и избегает исходный код дублирование; (2) хорошо выполненные приложения должны вызывать только экспортированные предикаты, и есть инструменты, которые могут обнаружить нарушение этого принципа. С другой стороны, включенный файл - это только сущность первого класса, которую вы рассматриваете как сам файл. Следует также проявлять осторожность при загрузке модулей, которые включают общий битовый файл, как использование, например, consult/1 или use_module/1 приведет к конфликтам:

?- [cat, dog]. 
% cat compiled into cat 0.00 sec, 4 clauses 
ERROR: import/1: No permission to import dog:move/1 into user (already imported from cat) 
% dog compiled into dog 0.00 sec, 4 clauses 
true. 

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

+1

Хороший ответ (+1), отношение между экспортом/1, include/1 очень неуловимо. Но я не уверен, что это решение подходит для вопроса OP. – CapelliC

+0

Моя интерпретация вопроса OP состоит в том, что он хочет иметь общий интерфейс и различные реализации для этого интерфейса (но это помогло бы получить от него больше информации). Таким образом, самым чистым решением является Logtalk, который в настоящее время сидит с нулевым голосом и даже имеет отрицательные голоса раньше. Но нисходящие избиратели предоставили до сих пор нулевые рабочие решения. Logtalk был разработан с учетом таких проблем. Модули Prolog были разработаны для нулевого накладного расхода, не предназначенные для решения таких проблем элегантно или вообще. Итак, неуловимое модульное решение - это лучшее, что вы можете сделать. –

Смежные вопросы