splitting facts and predicates between files

View: New views
10 Messages — Rating Filter:   Alert me  

splitting facts and predicates between files

by Guy Wiener :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

I am looking for the correct way to split the declarations of facts and
predicates between a module file and fact files.


The program that I write deals with a series of facts. These facts
should be declared in separate files. On top of these facts there are
some predicates. These predicates should be declared in a common file,
like a module.


For example, suppose that the facts are object/1 and consists/2. A fact
file would be something like:

object(foo).

object(goo).

object(zoo).

consists(foo, goo).

consists(goo, zoo).


The common module includes predicates like inside/2, which means that
one object is inside another:

inside(X, Y) :-

  object(X),

  object(Y),

  consists(X,Y).

inside(X, Y) :-

  inside(X, Z),

  object(Y),

  consists(Z, Y).


I would like to load the common module and then one or more fact files,
and then to have answers to queries such as "inside(A, zoo).".

What should be the module declaration? Should I also use other predicate
properties, such as multifile, discontiguous, module_transparent? I
couldn't find a good example for this scenario.


On a different note: I am currently developing an interesting
application in Prolog (I hope to publish it some day!) and I find this
mailing list invaluable. Thanks!


Guy Wiener.

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Paulo Moura :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 2009/09/10, at 10:27, Guy Wiener wrote:

> Hello,
>
> I am looking for the correct way to split the declarations of facts  
> and predicates between a module file and fact files.
>
>
> The program that I write deals with a series of facts. These facts  
> should be declared in separate files. On top of these facts there  
> are some predicates. These predicates should be declared in a common  
> file, like a module.
>
>
> For example, suppose that the facts are object/1 and consists/2. A  
> fact file would be something like:
>
> object(foo).
>
> object(goo).
>
> object(zoo).
>
> consists(foo, goo).
>
> consists(goo, zoo).
>
>
> The common module includes predicates like inside/2, which means  
> that one object is inside another:
>
> inside(X, Y) :-
>
> object(X),
>
> object(Y),
>
> consists(X,Y).
>
> inside(X, Y) :-
>
> inside(X, Z),
>
> object(Y),
>
> consists(Z, Y).
>
>
> I would like to load the common module and then one or more fact  
> files, and then to have answers to queries such as "inside(A, zoo).".
>
> What should be the module declaration? Should I also use other  
> predicate properties, such as multifile, discontiguous,  
> module_transparent? I couldn't find a good example for this scenario.


In Logtalk you could write something like:

:- object(common).

     :- public([object/1, consists/2, inside/2]).

     inside(X, Y) :-
         ::object(X),
         ::object(Y),
         ::consists(X, Y).
     inside(X, Y) :-
         inside(X, Z),
         object(Y),
         ::consists(Z, Y).

:- end_object.


:- object(facts, extends(common)).

     object(foo).
     object(goo).
     object(zoo).

     consists(foo, goo).
     consists(goo, zoo).

:- end_object.


This solution allows to load into memory any number of facts "files"  
you want. Simply copy the two Logtalk objects above to a source file,  
say, "objects.lgt", and try:

% swilgt
...
| ?- {objects}.
...
| ?- facts::inside(A, zoo).
...

You may create a source file per Logtalk object if you prefer. E.g.  
"common.lgt" and "facts.lgt":

| ?- {common, facts}.


Hope this helps. Cheers,

Paulo


-----------------------------------------------------------------
Paulo Jorge Lopes de Moura, PhD
Assistant Professor
Dep. of Computer Science, University of Beira Interior
6201-001 Covilhã, Portugal

Office 3.18  Ext. 3276
Phone: +351 275319891 Fax: +351 275319899
Email: <mailto:pmoura@...>

Home page: <http://www.di.ubi.pt/~pmoura>
Research:  <http://logtalk.org/> Blog: <http://blog.logtalk.org/>
-----------------------------------------------------------------

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Chris Mungall-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


You will probably want to use multifile/1. dynamic/1 is optional, it  
depends whether you want to assert new facts at runtime. For saving  
facts to a file you could use clause/2 to find all unit-clauses, or  
you could use a metamodel predicate to declare a predicates to be  
facts. Implicit in what you have below is a constraint that a  
predicate is either a fact/unit clause or a rule but never a mixture?

It would be nice to see some kind of standard library for this emerge.  
Some (slightly vague) requirements

- lightweight, and allows the user to avoid repeating him/herself
- it should play nicely with modules
- provide predicates such as load_facts, write_facts, etc
- optional typing info on the fact arguments, all the way up to sql-
style constraints
        e.g. :- fact(consists(object,object))
- some kind of hook into pldoc.
        E.g. it might be nice to write
        % consists(Part:object, Whole:object)
        and have everything else taken care of.

The dbmeta module in blip (http://blipkit.org) was written to satisfy  
some of these requirements. I would not recommend using this outright  
though, I wrote it a while ago and it's acquired a lot of cruft. May  
be a useful source of ideas though.

On Sep 10, 2009, at 2:27 AM, Guy Wiener wrote:

> Hello,
>
> I am looking for the correct way to split the declarations of facts  
> and predicates between a module file and fact files.
>
>
> The program that I write deals with a series of facts. These facts  
> should be declared in separate files. On top of these facts there  
> are some predicates. These predicates should be declared in a common  
> file, like a module.
>
>
> For example, suppose that the facts are object/1 and consists/2. A  
> fact file would be something like:
>
> object(foo).
>
> object(goo).
>
> object(zoo).
>
> consists(foo, goo).
>
> consists(goo, zoo).
>
>
> The common module includes predicates like inside/2, which means  
> that one object is inside another:
>
> inside(X, Y) :-
>
> object(X),
>
> object(Y),
>
> consists(X,Y).
>
> inside(X, Y) :-
>
> inside(X, Z),
>
> object(Y),
>
> consists(Z, Y).
>
>
> I would like to load the common module and then one or more fact  
> files, and then to have answers to queries such as "inside(A, zoo).".
>
> What should be the module declaration? Should I also use other  
> predicate properties, such as multifile, discontiguous,  
> module_transparent? I couldn't find a good example for this scenario.
>
>
> On a different note: I am currently developing an interesting  
> application in Prolog (I hope to publish it some day!) and I find  
> this mailing list invaluable. Thanks!
>
>
> Guy Wiener.
>
> _______________________________________________
> SWI-Prolog mailing list
> SWI-Prolog@...
> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Guy Wiener :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks! But, is having only predicates that are either facts or rules a
true constraints?
I thing I might have to use a mix of both.

Guy.

Chris Mungall wrote:

>
> You will probably want to use multifile/1. dynamic/1 is optional, it
> depends whether you want to assert new facts at runtime. For saving
> facts to a file you could use clause/2 to find all unit-clauses, or
> you could use a metamodel predicate to declare a predicates to be
> facts. Implicit in what you have below is a constraint that a
> predicate is either a fact/unit clause or a rule but never a mixture?
>
> It would be nice to see some kind of standard library for this emerge.
> Some (slightly vague) requirements
>
> - lightweight, and allows the user to avoid repeating him/herself
> - it should play nicely with modules
> - provide predicates such as load_facts, write_facts, etc
> - optional typing info on the fact arguments, all the way up to
> sql-style constraints
>     e.g. :- fact(consists(object,object))
> - some kind of hook into pldoc.
>     E.g. it might be nice to write
>     % consists(Part:object, Whole:object)
>     and have everything else taken care of.
>
> The dbmeta module in blip (http://blipkit.org) was written to satisfy
> some of these requirements. I would not recommend using this outright
> though, I wrote it a while ago and it's acquired a lot of cruft. May
> be a useful source of ideas though.
>
> On Sep 10, 2009, at 2:27 AM, Guy Wiener wrote:
>
>> Hello,
>>
>> I am looking for the correct way to split the declarations of facts
>> and predicates between a module file and fact files.
>>
>>
>> The program that I write deals with a series of facts. These facts
>> should be declared in separate files. On top of these facts there are
>> some predicates. These predicates should be declared in a common
>> file, like a module.
>>
>>
>> For example, suppose that the facts are object/1 and consists/2. A
>> fact file would be something like:
>>
>> object(foo).
>>
>> object(goo).
>>
>> object(zoo).
>>
>> consists(foo, goo).
>>
>> consists(goo, zoo).
>>
>>
>> The common module includes predicates like inside/2, which means that
>> one object is inside another:
>>
>> inside(X, Y) :-
>>
>> object(X),
>>
>> object(Y),
>>
>> consists(X,Y).
>>
>> inside(X, Y) :-
>>
>> inside(X, Z),
>>
>> object(Y),
>>
>> consists(Z, Y).
>>
>>
>> I would like to load the common module and then one or more fact
>> files, and then to have answers to queries such as "inside(A, zoo).".
>>
>> What should be the module declaration? Should I also use other
>> predicate properties, such as multifile, discontiguous,
>> module_transparent? I couldn't find a good example for this scenario.
>>
>>
>> On a different note: I am currently developing an interesting
>> application in Prolog (I hope to publish it some day!) and I find
>> this mailing list invaluable. Thanks!
>>
>>
>> Guy Wiener.
>>
>> _______________________________________________
>> SWI-Prolog mailing list
>> SWI-Prolog@...
>> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>>
>
> _______________________________________________
> SWI-Prolog mailing list
> SWI-Prolog@...
> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Chris Mungall-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mixing should be fine. For your purposes it may be sufficient to  
declare your predicate as multifile and then just load the module and  
fact files using normal prolog predicates such as use_module/1 and  
consult/1. qcompile/1 is useful for large factfiles.

Beware that multifile/1 acts a little differently in different prolog  
systems.

On Sep 10, 2009, at 12:28 PM, Guy Wiener wrote:

> Thanks! But, is having only predicates that are either facts or  
> rules a true constraints?
> I thing I might have to use a mix of both.
>
> Guy.
>
> Chris Mungall wrote:
>>
>> You will probably want to use multifile/1. dynamic/1 is optional,  
>> it depends whether you want to assert new facts at runtime. For  
>> saving facts to a file you could use clause/2 to find all unit-
>> clauses, or you could use a metamodel predicate to declare a  
>> predicates to be facts. Implicit in what you have below is a  
>> constraint that a predicate is either a fact/unit clause or a rule  
>> but never a mixture?
>>
>> It would be nice to see some kind of standard library for this  
>> emerge. Some (slightly vague) requirements
>>
>> - lightweight, and allows the user to avoid repeating him/herself
>> - it should play nicely with modules
>> - provide predicates such as load_facts, write_facts, etc
>> - optional typing info on the fact arguments, all the way up to sql-
>> style constraints
>>    e.g. :- fact(consists(object,object))
>> - some kind of hook into pldoc.
>>    E.g. it might be nice to write
>>    % consists(Part:object, Whole:object)
>>    and have everything else taken care of.
>>
>> The dbmeta module in blip (http://blipkit.org) was written to  
>> satisfy some of these requirements. I would not recommend using  
>> this outright though, I wrote it a while ago and it's acquired a  
>> lot of cruft. May be a useful source of ideas though.
>>
>> On Sep 10, 2009, at 2:27 AM, Guy Wiener wrote:
>>
>>> Hello,
>>>
>>> I am looking for the correct way to split the declarations of  
>>> facts and predicates between a module file and fact files.
>>>
>>>
>>> The program that I write deals with a series of facts. These facts  
>>> should be declared in separate files. On top of these facts there  
>>> are some predicates. These predicates should be declared in a  
>>> common file, like a module.
>>>
>>>
>>> For example, suppose that the facts are object/1 and consists/2. A  
>>> fact file would be something like:
>>>
>>> object(foo).
>>>
>>> object(goo).
>>>
>>> object(zoo).
>>>
>>> consists(foo, goo).
>>>
>>> consists(goo, zoo).
>>>
>>>
>>> The common module includes predicates like inside/2, which means  
>>> that one object is inside another:
>>>
>>> inside(X, Y) :-
>>>
>>> object(X),
>>>
>>> object(Y),
>>>
>>> consists(X,Y).
>>>
>>> inside(X, Y) :-
>>>
>>> inside(X, Z),
>>>
>>> object(Y),
>>>
>>> consists(Z, Y).
>>>
>>>
>>> I would like to load the common module and then one or more fact  
>>> files, and then to have answers to queries such as "inside(A,  
>>> zoo).".
>>>
>>> What should be the module declaration? Should I also use other  
>>> predicate properties, such as multifile, discontiguous,  
>>> module_transparent? I couldn't find a good example for this  
>>> scenario.
>>>
>>>
>>> On a different note: I am currently developing an interesting  
>>> application in Prolog (I hope to publish it some day!) and I find  
>>> this mailing list invaluable. Thanks!
>>>
>>>
>>> Guy Wiener.
>>>
>>> _______________________________________________
>>> SWI-Prolog mailing list
>>> SWI-Prolog@...
>>> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>>>
>>
>> _______________________________________________
>> SWI-Prolog mailing list
>> SWI-Prolog@...
>> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>
> _______________________________________________
> SWI-Prolog mailing list
> SWI-Prolog@...
> https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Günter Kniesel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Paulo Moura schrieb:
>
> On 2009/09/10, at 10:27, Guy Wiener wrote:
>
>> Hello,
>>
>> I am looking for the correct way to split the declarations of facts
>> and predicates between a module file and fact files.
...
>> I would like to load the common module and then one or more fact
>> files, and then to have answers to queries such as "inside(A, zoo).".
>>
...
>
> In Logtalk you could write something like:
...
> | ?- facts::inside(A, zoo).

Hi Paulo, hi Guy,

the LogTalk solution is elegant but Guy asked for a solution where
he could simply query "?-inside(A, zoo)", without explicitly
addressing one of the different fact files. That would need a
message addressed to a variable receiver, such as

  ?- AnyObject::inside(A, zoo).

Is that legal in LogTalk? I gueess it is.

If not, or if Guy was looking for a solution that runs in plain
SWI Prolog without the LogTalk extension, here is a quite
straightforward rewrite of Paulos solution that achieves both.

Günter

PS: The code below contains two modifications not related to the
     translation from LogTalk:
      - moved recursive call of "inside" to the of the clause to
        assure termination
      - renamed "object" to "obj" since "object" collides with the
        predicate defined in PCE.

%-------------------------- File "common.pl" ----------------------

/** LogTalk2SWI translation scheme: Copied Paulos Logtalk code and
   replaced
    - the "object" declarations by "module/2" declarations,
    - the "public" declarations by module export,
    - the object extension declaration by "use_module/1" and
    - the :: operator by normal module qualifier and the use of
          "context_module/1".
   For all this to work as intended one must declare the "inheritable"
   predicates of the module "common" as "module_transparent".

   This illustrates a simple idiom for OO programming in SWI-Prolog.
   [Or better say "object-based" programming since we are simulating
   class-less objects that delegate to each other (no classes and no
   class-based inheritance). "Self" is the archetype of such languages.]
**/


:- module(common, [inside/2]).

:- module_transparent inside/2.  % Enforce dynamic binding of "context module"

     inside(X, Y) :- context_module(M),
         M:obj(X),
         M:obj(Y),
         M:consists(X, Y).
     inside(X, Y) :- context_module(M),
         M:obj(Y),
         M:consists(Z, Y),
         inside(X, Z).

%-------------------------- File facts1.pl" ----------------------
:- module(facts1, []).
:- consult(common).

     obj(foo).
     obj(goo).
     obj(zoo).

     consists(foo, goo).
     consists(goo, zoo).



%-------------------------- File "facts2.pl" ----------------------
:- module(facts2,[]).
:- consult(common).

     obj(foo2).
     obj(goo2).
     obj(zoo).

     consists(foo2, goo2).
     consists(goo2, zoo).


%-------------------------- Try in the console  ------------------------

:- consult(facts1).
:- consult(facts2).

% Call to a specific module:
?- facts1:inside(A, zoo).

% Call to any module that might possibly contribute a solution:
?- current_predicate(Module:inside(_,_)),
    Module:catch(inside(A, zoo),_,fail).

    % <-- the "catch" is essential to skip modules
    % in which some predicate is not defined. SWI-Prlog
    % would otherwise abort the goal because of an
    % "Undefined procedure" error even if there are
    % other modules left in which the goal will succeed.


--------------------------------------------------------------------
Dr. Günter Kniesel                    http://www.cs.uni-bonn.de/~gk/
Institut für Informatik III                        gk@...
Universität Bonn
Römerstr. 164 (Raum A107)                      Tel (+49 228) 73-4511
D-53117 Bonn                                   Fax (+49 228) 73-4382
_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: splitting facts and predicates between files

by Paulo Moura :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 2009/09/18, at 14:52, Günter Kniesel wrote:

> Paulo Moura schrieb:
>> On 2009/09/10, at 10:27, Guy Wiener wrote:
>>> Hello,
>>>
>>> I am looking for the correct way to split the declarations of  
>>> facts and predicates between a module file and fact files.
> ...
>>> I would like to load the common module and then one or more fact  
>>> files, and then to have answers to queries such as "inside(A,  
>>> zoo).".
>>>
> ...
>> In Logtalk you could write something like:
> ...
>> | ?- facts::inside(A, zoo).
>
> Hi Paulo, hi Guy,
>
> the LogTalk solution is elegant but Guy asked for a solution where
> he could simply query "?-inside(A, zoo)", without explicitly
> addressing one of the different fact files.

Logtalk, not LogTalk. Please leave CamelCase to Java programmers ;-)

Your solution below also doesn't seem to support the simply query "?-
inside(A, zoo)", without explicitly addressing one of the different  
fact files.

> That would need a
> message addressed to a variable receiver, such as
>
> ?- AnyObject::inside(A, zoo).
>
> Is that legal in LogTalk? I gueess it is.

No. You may, however, enumerate by backtracking all the objects that  
accept the inside/2 message to get the same functionality. For example:

| ?- extends_object(Object, common), Object::inside(A, zoo).

This is basically the same solution (based on reflection built-in  
predicates) that you use below with modules. You could also write:

| ?- current_object(Object), Object::current_predicate(inside/1),  
Object::inside(A, zoo).

> If not, or if Guy was looking for a solution that runs in plain
> SWI Prolog without the LogTalk extension, here is a quite
> straightforward rewrite of Paulos solution that achieves both.
>
> Günter
>
> PS: The code below contains two modifications not related to the
>    translation from LogTalk:
>     - moved recursive call of "inside" to the of the clause to
>       assure termination
>     - renamed "object" to "obj" since "object" collides with the
>       predicate defined in PCE.
>
> %-------------------------- File "common.pl" ----------------------
>
> /** LogTalk2SWI translation scheme: Copied Paulos Logtalk code and
>  replaced
>   - the "object" declarations by "module/2" declarations,
>   - the "public" declarations by module export,
>   - the object extension declaration by "use_module/1" and
>   - the :: operator by normal module qualifier and the use of
>         "context_module/1".
>  For all this to work as intended one must declare the "inheritable"
>  predicates of the module "common" as "module_transparent".

I believe that the legacy (?) directive module_transparent/1 should be  
avoided. New code should preferably use the standard directive  
meta_predicate/1.

>  This illustrates a simple idiom for OO programming in SWI-Prolog.
>  [Or better say "object-based" programming since we are simulating
>  class-less objects that delegate to each other (no classes and no
>  class-based inheritance). "Self" is the archetype of such languages.]

Logtalk supports both classes and prototypes (Self is a prototype-
based OOP language). Btw, the solution I posted uses prototypes, not  
classes (the source of the misunderstanding might be that Java uses a  
"extends" keyword for class specialization where Logtalk uses  
"extends" for parent-prototype relations and "specializes" for class  
specialization).

> **/
>
>
> :- module(common, [inside/2]).
>
> :- module_transparent inside/2.  % Enforce dynamic binding of  
> "context module"
> ...
> %-------------------------- Try in the console  
> ------------------------
>
> :- consult(facts1).
> :- consult(facts2).
>
> % Call to a specific module:
> ?- facts1:inside(A, zoo).
>
> % Call to any module that might possibly contribute a solution:
> ?- current_predicate(Module:inside(_,_)),
>   Module:catch(inside(A, zoo),_,fail).
>
>   % <-- the "catch" is essential to skip modules
>   % in which some predicate is not defined. SWI-Prlog
>   % would otherwise abort the goal because of an
>   % "Undefined procedure" error even if there are
>   % other modules left in which the goal will succeed.


The catch/3 wrapper results from a lack of distinction between  
declaring a predicate and defining a predicate. No such issue in  
Logtalk where calls to declared but not defined predicates simply fail  
(think closed-world assumption).

I tried to extend your code by writing a new module, "root":

:- module(root, [outside/2]).

:- module_transparent outside/2.  % Enforce dynamic binding of  
"context module"

    outside(X, Y) :- context_module(M),
        M:obj(X),
        M:obj(Y),
        M:consists(Y, X).
    outside(X, Y) :- context_module(M),
        M:obj(Y),
        M:consists(Y, Z),
        outside(Z, X).

and then modifying the module "common" to "inherit" from the module  
"root":

:- module(common, [inside/2]).
:- consult(root).
...

However, this doesn't seem to work as desired:

?- [facts1, facts2].
%   root compiled into root 0.00 sec, 1,148 bytes
%  common compiled into common 0.00 sec, 2,352 bytes
% facts1 compiled into facts1 0.00 sec, 3,780 bytes
%   root compiled into root 0.00 sec, 0 bytes
%  common compiled into common 0.00 sec, 564 bytes
% facts2 compiled into facts2 0.00 sec, 1,692 bytes
true.

?- facts1:outside(X, Y).
Correct to: "root:outside(X, Y)"? no
ERROR: '$execute_goal2'/2: Undefined procedure: facts1:outside/2
?- facts1:outside(X, Y).
Correct to: "root:outside(X, Y)"? yes
ERROR: root:outside/2: Undefined procedure: root:obj/1
^  Exception: (7) root:outside(_G230, _G231) ? creep

Do you think it's possible to simulate inheritance in a "module  
hierarchy" that is more than two levels deep?

Cheers,

Paulo


-----------------------------------------------------------------
Paulo Jorge Lopes de Moura, PhD
Assistant Professor
Dep. of Computer Science, University of Beira Interior
6201-001 Covilhã, Portugal

Office 3.18  Ext. 3276
Phone: +351 275319891 Fax: +351 275319899
Email: <mailto:pmoura@...>

Home page: <http://www.di.ubi.pt/~pmoura>
Research:  <http://logtalk.org/> Blog: <http://blog.logtalk.org/>
-----------------------------------------------------------------

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

OOP in SWI (was: splitting facts and predicates between files)

by Günter Kniesel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Paulo,

thanks for your quick reply and sorry for letting you wait.

Paulo Moura wrote:

> Logtalk, not LogTalk. Please leave CamelCase to Java programmers ;-)

Sorry. I'll remember that it's like Smalltalk ;)

> Your solution below also doesn't seem to support the simply query
> "?-inside(A, zoo)", without explicitly addressing one of the different
> fact files.

It does. Please note that in the query

?- current_predicate(_, Module:inside(_,_)),
    Module:catch(inside(A, zoo),_,fail).

the "Module" is a free variable. So you don't need to know all the
objects in advance but can simply ask the query and get back the
results AND the objects that provide them.

> This is basically the same solution (based on reflection built-in
> predicates) that you use below with modules. You could also write:
>
> | ?- current_object(Object), Object::current_predicate(inside/1),
>                              Object::inside(A, zoo).

This indeed looks pretty much equivalent to the above two lines of SWI code.

>>  This illustrates a simple idiom for OO programming in SWI-Prolog.
>>  [Or better say "object-based" programming since we are simulating
>>  class-less objects that delegate to each other (no classes and no
>>  class-based inheritance). "Self" is the archetype of such languages.]
>
> Logtalk supports both classes and prototypes (Self is a prototype-based
> OOP language). Btw, the solution I posted uses prototypes, not classes
> (the source of the misunderstanding might be that Java uses a "extends"
> keyword for class specialization where Logtalk uses "extends" for
> parent-prototype relations and "specializes" for class specialization).
We violently agree ;) My sentence did not refer to Logtalk, just to
the simulation that I suggested -- which is definitely object-based
(or prototype-based if you prefer the term).


>> % Call to any module that might possibly contribute a solution:
>> ?- current_predicate(Module:inside(_,_)),
>>   Module:catch(inside(A, zoo),_,fail).
>>
>>   % <-- the "catch" is essential to skip modules
>>   % in which some predicate is not defined. SWI-Prlog
>>   % would otherwise abort the goal because of an
>>   % "Undefined procedure" error even if there are
>>   % other modules left in which the goal will succeed.
>
> The catch/3 wrapper results from a lack of distinction between declaring
> a predicate and defining a predicate. No such issue in Logtalk where
> calls to declared but not defined predicates simply fail (think
> closed-world assumption).
In general, I'd prefer the goal to silently fails in both cases (when a
predicate is undeclared AND when it is undefined). However, different
applications have different requirements so ideally there should be an
option to control whether it fails or whether it trows an exception.

> I tried to extend your code by writing a new module, "root":
>
> :- module(root, [outside/2]).
>
> :- module_transparent outside/2.  % Enforce dynamic binding of "context
> module"
>
>    outside(X, Y) :- context_module(M),
>        M:obj(X),
>        M:obj(Y),
>        M:consists(Y, X).
>    outside(X, Y) :- context_module(M),
>        M:obj(Y),
>        M:consists(Y, Z),
>        outside(Z, X).
>
> and then modifying the module "common" to "inherit" from the module "root":
>
> :- module(common, [inside/2]).
> :- consult(root).
> ...
>
> However, this doesn't seem to work as desired:
...
> Do you think it's possible to simulate inheritance in a "module
> hierarchy" that is more than two levels deep?

Sure. Simply add the inherited predicates to the export list of the
inheriting module if you want them to be inherited by its children.

In your example simply modify

:- module(common, [inside/2]).
to
:- module(common, [inside/2, outside/2]).

I've attached a zip file with the complete example including the results
of the goals we discussed.

Regards,
Günter



oop_in_prolog.zip (5K) Download Attachment

Re: OOP in SWI (was: splitting facts and predicates between files)

by Paulo Moura :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 2009/09/22, at 19:21, Günter Kniesel wrote:

> Hi Paulo,
>
> thanks for your quick reply and sorry for letting you wait.
>
> Paulo Moura wrote:
>
>> Logtalk, not LogTalk. Please leave CamelCase to Java programmers ;-)
>
> Sorry. I'll remember that it's like Smalltalk ;)
>
>> Your solution below also doesn't seem to support the simply query  
>> "?-inside(A, zoo)", without explicitly addressing one of the  
>> different fact files.
>
> It does. Please note that in the query
>
> ?- current_predicate(_, Module:inside(_,_)),
>   Module:catch(inside(A, zoo),_,fail).
>
> the "Module" is a free variable. So you don't need to know all the
> objects in advance but can simply ask the query and get back the
> results AND the objects that provide them.
>
>> This is basically the same solution (based on reflection built-in  
>> predicates) that you use below with modules. You could also write:
>> | ?- current_object(Object), Object::current_predicate(inside/
>> 1),                              Object::inside(A, zoo).
>
> This indeed looks pretty much equivalent to the above two lines of  
> SWI code.

Yes, both solutions are basically the same :-)

>>> % Call to any module that might possibly contribute a solution:
>>> ?- current_predicate(Module:inside(_,_)),
>>>  Module:catch(inside(A, zoo),_,fail).
>>>
>>>  % <-- the "catch" is essential to skip modules
>>>  % in which some predicate is not defined. SWI-Prlog
>>>  % would otherwise abort the goal because of an
>>>  % "Undefined procedure" error even if there are
>>>  % other modules left in which the goal will succeed.
>> The catch/3 wrapper results from a lack of distinction between  
>> declaring a predicate and defining a predicate. No such issue in  
>> Logtalk where calls to declared but not defined predicates simply  
>> fail (think closed-world assumption).
>
> In general, I'd prefer the goal to silently fails in both cases  
> (when a
> predicate is undeclared AND when it is undefined). However, different
> applications have different requirements so ideally there should be an
> option to control whether it fails or whether it trows an exception.

Making the standard Prolog flag "unknown" local to a module/object  
could provide such an option.

>> I tried to extend your code by writing a new module, "root":
>> :- module(root, [outside/2]).
>> :- module_transparent outside/2.  % Enforce dynamic binding of  
>> "context module"
>>   outside(X, Y) :- context_module(M),
>>       M:obj(X),
>>       M:obj(Y),
>>       M:consists(Y, X).
>>   outside(X, Y) :- context_module(M),
>>       M:obj(Y),
>>       M:consists(Y, Z),
>>       outside(Z, X).
>> and then modifying the module "common" to "inherit" from the module  
>> "root":
>> :- module(common, [inside/2]).
>> :- consult(root).
>> ...
>> However, this doesn't seem to work as desired:
> ...
>> Do you think it's possible to simulate inheritance in a "module  
>> hierarchy" that is more than two levels deep?
>
> Sure. Simply add the inherited predicates to the export list of the
> inheriting module if you want them to be inherited by its children.
>
> In your example simply modify
>
> :- module(common, [inside/2]).
> to
> :- module(common, [inside/2, outside/2]).
>
> I've attached a zip file with the complete example including the  
> results
> of the goals we discussed.


Nice, lightweight solution. Thanks for sharing :-)

Cheers,

Paulo


-----------------------------------------------------------------
Paulo Jorge Lopes de Moura, PhD
Assistant Professor
Dep. of Computer Science, University of Beira Interior
6201-001 Covilhã, Portugal

Office 3.18  Ext. 3276
Phone: +351 275319891 Fax: +351 275319899
Email: <mailto:pmoura@...>

Home page: <http://www.di.ubi.pt/~pmoura>
Research:  <http://logtalk.org/> Blog: <http://blog.logtalk.org/>
-----------------------------------------------------------------

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: OOP in SWI

by Günter Kniesel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Paulo Moura schrieb:

>
> On 2009/09/22, at 19:21, Günter Kniesel wrote:
>
>> Hi Paulo,
>>
>> thanks for your quick reply and sorry for letting you wait.
>>
>> Paulo Moura wrote:
>>
>>> Logtalk, not LogTalk. Please leave CamelCase to Java programmers ;-)
>>
>> Sorry. I'll remember that it's like Smalltalk ;)
>>
>>> Your solution below also doesn't seem to support the simply query
>>> "?-inside(A, zoo)", without explicitly addressing one of the
>>> different fact files.
>>
>> It does. Please note that in the query
>>
>> ?- current_predicate(_, Module:inside(_,_)),
>>   Module:catch(inside(A, zoo),_,fail).
>>
>> the "Module" is a free variable. So you don't need to know all the
>> objects in advance but can simply ask the query and get back the
>> results AND the objects that provide them.
>>
>>> This is basically the same solution (based on reflection built-in
>>> predicates) that you use below with modules. You could also write:
>>> | ?- current_object(Object),
>>> Object::current_predicate(inside/1),                              
>>> Object::inside(A, zoo).
>>
>> This indeed looks pretty much equivalent to the above two lines of SWI
>> code.
>
> Yes, both solutions are basically the same :-)
>
>>>> % Call to any module that might possibly contribute a solution:
>>>> ?- current_predicate(Module:inside(_,_)),
>>>>  Module:catch(inside(A, zoo),_,fail).
>>>>
>>>>  % <-- the "catch" is essential to skip modules
>>>>  % in which some predicate is not defined. SWI-Prlog
>>>>  % would otherwise abort the goal because of an
>>>>  % "Undefined procedure" error even if there are
>>>>  % other modules left in which the goal will succeed.
>>> The catch/3 wrapper results from a lack of distinction between
>>> declaring a predicate and defining a predicate. No such issue in
>>> Logtalk where calls to declared but not defined predicates simply
>>> fail (think closed-world assumption).
>>
>> In general, I'd prefer the goal to silently fails in both cases (when a
>> predicate is undeclared AND when it is undefined). However, different
>> applications have different requirements so ideally there should be an
>> option to control whether it fails or whether it trows an exception.
>
> Making the standard Prolog flag "unknown" local to a module/object could
> provide such an option.
>
>>> I tried to extend your code by writing a new module, "root":
>>> :- module(root, [outside/2]).
>>> :- module_transparent outside/2.  % Enforce dynamic binding of
>>> "context module"
>>>   outside(X, Y) :- context_module(M),
>>>       M:obj(X),
>>>       M:obj(Y),
>>>       M:consists(Y, X).
>>>   outside(X, Y) :- context_module(M),
>>>       M:obj(Y),
>>>       M:consists(Y, Z),
>>>       outside(Z, X).
>>> and then modifying the module "common" to "inherit" from the module
>>> "root":
>>> :- module(common, [inside/2]).
>>> :- consult(root).
>>> ...
>>> However, this doesn't seem to work as desired:
>> ...
>>> Do you think it's possible to simulate inheritance in a "module
>>> hierarchy" that is more than two levels deep?
>>
>> Sure. Simply add the inherited predicates to the export list of the
>> inheriting module if you want them to be inherited by its children.
>>
>> In your example simply modify
>>
>> :- module(common, [inside/2]).
>> to
>> :- module(common, [inside/2, outside/2]).
>>
>> I've attached a zip file with the complete example including the results
>> of the goals we discussed.
>
>
> Nice, lightweight solution. Thanks for sharing :-)

You're welcome.

By the way, one could use "use_module" and "reexport/1" to make
the above even a bit easier. "reexport" should avoid the need to
repeat the transitively inherited predicates manually in the own
export list. In the above case, one could write:

:- module(common, [inside/2]).
:- reexport(root).

Cheers,
Günter
_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog