Пролог: разница между переопределением предиката и его использованием - PullRequest
0 голосов
/ 29 сентября 2018

Я чувствую себя действительно глупо и чувствую, что что-то упустил.

У меня в основном есть два файла:

  • module.pl для универсальных логических правил (подразумеваетсядля повторного использования)
  • state.pl один для текущего сценария

В файле модуля (module.pl) я объявил:

inside(Food,Eater,T) :-
    isTime(T),
    injestEvent(InjEvent),
    justAfter(T,InjEvent),
    actorOfEvent(InjEvent, Eater),
    objectOfEvent(InjEvent, Food).

Q1) Я должен был объявить все эти другие предикаты с одноэлементными переменными (в том же файле), просто чтобы остановить module.pl жалобы, что они не существуют:

isTime(_T).
justAfter(_Time,_Event).

actorOfEvent(_Event, _ActorOfEvent).
objectOfEvent(_Event,_ActorOfEvent).

Это правильно?

Q2) Я не могу использовать эти предикаты, такие как justAfter/2 мой другой файл без него:

Локальное определение пользователя: justAfter / 2 отменяет слабый импорт из модуля

Как я могу использовать предикаты, которые я импортировал из моего модуля, а не переопределить его?

Ответы [ 3 ]

0 голосов
/ 30 сентября 2018

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

:- module(logic, [inside/4]).

% apply the rule to a specified module (expected to be a state object)
inside(M,Food,Eater,T) :-
    M:isTime(T),
    M:injestEvent(InjEvent),
    M:justAfter(T, InjEvent),
    M:actorOfEvent(InjEvent, Eater),
    M:objectOfEvent(InjEvent, Food).

, и у нас есть много соответствующих объектов состояния: в файле state1.pl

isTime(10).
injestEvent(eat).
justAfter(10, eat).
actorOfEvent(eat, mick).
objectOfEvent(eat, food).

и в файле state2.pl

isTime(20).
injestEvent(sleep).
justAfter(20, sleep).
actorOfEvent(sleep, everyone).
objectOfEvent(sleep, dream).

затем возможный сеанс:

?- [logic].
true.

?- s1:consult(state1).
true.

?- s2:consult(state2).
true.

?- inside(s1,Food,Eater,T).
Food = food,
Eater = mick,
T = 10.

?- inside(s2,What,Who,T).
What = dream,
Who = everyone,
T = 20.

Небольшое обобщение, которое стоит попробовать:

inside(M,Food,Eater,T) :-
    resolve(M),
    M:isTime(T),
    ...

, где разрешение / 1 может быть

resolve(M) :- var(M) -> current_module(M), catch(M:isTime(_),_,fail) ; true.

этот трюк включает «просмотр объектов»:

?- inside(M,X,Y,Z).
M = s2,
X = dream,
Y = everyone,
Z = 20 ;
M = s1,
X = food,
Y = mick,
Z = 10 ;
false.
0 голосов
/ 30 сентября 2018

Альтернативой CapelliC является использование Прологовых диктов .Они были представлены SWI-Prolog, и начиная с версии 1.3.0 они также доступны в Jekejeke Prolog.Если получатель не нужен, можно просто использовать подчеркивание.

Файл state1.pl:

:- module(state1, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 10.
_.injestEvent() := eat.
_.justAfter(10) := eat.
_.actorOfEvent(eat) := mick.
_.objectOfEvent(eat) := food.

Файл state2.pl:

:- module(state2, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 20.
_.injestEvent() := sleep.
_.justAfter(20) := sleep.
_.actorOfEvent(sleep) := everyone.
_.objectOfEvent(sleep) := dream.

Файл logic.pl:

:- module(logic, [inside/4]).
M.inside(Food,Eater) := T :-
    T = M.isTime(),
    InjEvent = M.injestEvent(),
    InjEvent = M.justAfter(T),
    Eater = M.actorOfEvent(InjEvent),
    Food = M.objectOfEvent(InjEvent).

Чтобы сделать логику также видимой в state1 и state2, используйте reexport / 1.Это позволяет отправить сообщение в состояние1 или состояние2, но, тем не менее, метод из логики будет обработан.Вот пример запуска:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.19)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick.

?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone.

Экспорт isTime / 2, injestEvent / 2 и т. Д. Исчезнет с выходом 1.3.1 Jekejeke Prolog, когда мы выполним ('.') / 3 Call-сайт осведомлен.Но результат для Jekejeke Prolog тот же:

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick

?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone
0 голосов
/ 29 сентября 2018

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

----- module.pl -----
:- module(module, [
    inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).

inside(Food,Eater,T) :-
    isTime(T),
    injestEvent(InjEvent),
    justAfter(T,InjEvent),
    actorOfEvent(InjEvent, Eater),
    objectOfEvent(InjEvent, Food).
---------------------

, что приводит к:

?- [module].
ERROR: Exported procedure module:justAfter/2 is not defined
ERROR: Exported procedure module:isTime/1 is not defined
ERROR: Exported procedure module:injestEvent/1 is not defined
ERROR: Exported procedure module:objectOfEvent/2 is not defined
ERROR: Exported procedure module:actorOfEvent/2 is not defined
true.

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

?- use_module(module).

Вы импортируете все предикаты, экспортированные на module, включая те, которые вы хотите определить в state.pl.Поэтому при загрузке state.pl компилятор предупреждает, что этот файл переопределяет эти предикаты.Например:

----- state.pl -----
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
--------------------

мы получаем:

?- [state].
Warning: /Users/pmoura/Desktop/state.pl:1:
    Local definition of user:isTime/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:2:
    Local definition of user:injestEvent/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:3:
    Local definition of user:justAfter/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:4:
    Local definition of user:actorOfEvent/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:5:
    Local definition of user:objectOfEvent/2 overrides weak import from module
true.

Хотя это предупреждения , а не ошибки, вызов предиката inside/3 будет не дать вам то, что вы хотите:

?- inside(Food,Eater,T).
true.

Где привязки?!?Давайте проследим вызов, чтобы выделить причину:

?- trace.
true.

[trace]  ?- inside(Food,Eater,T).
   Call: (8) module:inside(_2508, _2510, _2512) ? creep
   Call: (9) module:isTime(_2512) ? creep
   Exit: (9) module:isTime(_2512) ? creep
   Call: (9) module:injestEvent(_2804) ? creep
   Exit: (9) module:injestEvent(_2804) ? creep
   Call: (9) module:justAfter(_2512, _2806) ? creep
   Exit: (9) module:justAfter(_2512, _2806) ? creep
   Call: (9) module:actorOfEvent(_2804, _2510) ? creep
   Exit: (9) module:actorOfEvent(_2804, _2510) ? creep
   Call: (9) module:objectOfEvent(_2804, _2508) ? creep
   Exit: (9) module:objectOfEvent(_2804, _2508) ? creep
   Exit: (8) module:inside(_2508, _2510, _2512) ? creep
true.

Трассировка проясняет, что предикаты «состояния» вызываются в неверном контексте.

AЧистое решение - использовать объекты Logtalk вместо модулей Prolog.Logtalk расширяет Prolog и поддерживает большинство систем, включая SWI-Prolog.Он поддерживает интерфейсы / протоколы как первоклассные объекты (которые решают первую упомянутую вами проблему) и поддерживает наследование и вызов предикатов в их контексте использования (который решает вторую проблему).Вы можете использовать, например,

----- common.lgt -----
:- object(common).

:- public([
    inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).

inside(Food,Eater,T) :-
    % call the next predicates in "self", i.e. in the
    % object that received the inside/3 message
    ::isTime(T),
    ::injestEvent(InjEvent),
    ::justAfter(T,InjEvent),
    ::actorOfEvent(InjEvent, Eater),
    ::objectOfEvent(InjEvent, Food).

:- end_object.
----------------------

и затем представлять «состояние» как:

----- state.lgt -----
:- object(state, extends(common)).

isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).

:- end_object.
---------------------

Быстрый тест (после установки Logtalk):

$ swilgt
...
?- {common, state}.
...
true.

?- state::inside(Food,Eater,T).
Food = food,
Eater = eater,
T = 1.

КакБонус, вы можете определить столько «государственных» объектов, сколько вам нужно.Вы также можете иметь определения по умолчанию для предикатов "state" в объекте common.Они будут наследоваться и использоваться, когда объекты «состояния» не предоставляют определения для конкретного предиката.Например, давайте добавим к common предложение:

objectOfEvent(injEvent, drink).

и удалим (или закомментируем) предложение objectOfEvent(injEvent, food). из state.Сохраните, перезагрузите и повторите запрос:

?- {*}.   % abbreviation for Logtalk's make
% Redefining object common
...
% Redefining object state
...
true.

?- state::inside(Food,Eater,T).
Food = drink,
Eater = eater,
T = 1.

При необходимости вы также можете динамически создавать новые объекты состояния вместо определения их в исходных файлах.Например:

?- create_object(s2, [extends(common)], [], [isTime(42), ...]).

Этот может не быть ответом, который вы искали, но это также тот случай, когда лучший ответ - использовать правильный инструмент ^ H ^ H ^ H^ H механизм инкапсуляции для работы.Ваш шаблон программирования также является довольно распространенным (и одна из причин, по которой был разработан Logtalk).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...