How to separate files in prolog - prolog

I wanna know if it´s possible to separate files in prolog, for example:
I wanna have my interface, rules, facts, consults in separate files and make them work together.

Yes - look at 'modules' in the SWI-Prolog documentation.
In short, you consult one file and it loads the others. So, say you have a.pl, b.pl, and so on
here's b.pl
bear(X) :- write('I see a bear named '), writeln(X).
bull(X) :- write('I see a bull named '), writeln(X).
at top of b.pl
put
:- module(b, [bear/1]).
Now you can use bear (the /1 means 'with one argument') outside this file.
in a.pl put
:- use_module(b).
Notice that there's no .pl on that
and then you can refer to bear
final program
a.pl
:- use_module(b).
go :- bear('Yogi').
b.pl
:- module(b, [bear/1]).
bear(X) :- write('I see a bear named '), writeln(X).
bull(X) :- write('I see a bull named '), writeln(X).
This way you can make things like bull/1 private to a single module.

Short answer, yes. Long answer, depends on what you mean by "interface" and how simple or complex are your requirements. As mbratch pointed out, the ISO Prolog standard include/1 directive can be used to include e.g. a set of predicate directives in files containing definitions for those predicates. If, on the other hand, your application requires multiple implementations of the same interface, you may be able to use Prolog modules together with the include/1 directive where each module would provide an implementation depending on what you want as an interface or use Logtalk, which provides interfaces as a first class entity. A more sound advice and detailed answer, however, requires on you providing more information on what you're trying to accomplish.

Related

How to assert multiple facts or rules in one assert/1 statement?

If I'm at the repl I can do
?- assert(foo(a)),assert(foo(b)),assert(foo(c)).
and that works, but not
?- assert((bar(a),bar(b),bar(c))).
or similar. Is there a way to only need to type "assert" once and pass in multiple facts? Same question for rules.
thanks!
I tried several variations of what I mentioned above to accomplish this but can't figure out how to do it. Also looked at the doc for assert/1 but it doesn't show how.
Maybe you can instead consult from user?
?- [user].
:- dynamic(foo/1).
foo(a).
foo(b).
foo(c).
Press Ctrl-D to end consulting. If you just want to add clauses the database, you may not need to type the dynamic/1 directive.
P.S. assert/1 is a deprecated/legacy predicate. Use instead assrta/1 or assertz/1 if you must.

Prolog term_expansion not working

I am trying to perform the following term_expansion with swipl:
a(asda).
a(astronaut).
term_expansion(a(X),b(X)).
But it does not work, i.e. there is no b/1 consulted. I have tried a few variations:
term_expansion(a(X),[b(X)]).
user:term_expansion(a(X),b(X)).
user:term_expansion(a(X),[b(X)]).
user:term_expansion(user:a(X),[user:b(X)]).
None of which works. What is the problem?
As explained by #mat, you need to define the term_expansion/2 predicate before the clauses you want to expand are loaded. Also, the term_expansion/2 predicate is a multifile and dynamic predicate defined for the user pseudo-module. Thus, you should write:
:- multifile user:term_expansion/2.
:- dynamic user:term_expansion/2.
user:term_expansion(a(X), b(X)).
This will ensure that your expansion code will work if you move it into a module.
If portability to other Prolog systems with a term-expansion mechanism (which, btw, is far from standard), than consider moving the term-expansion code to its own file, loaded before the source files you want to expand.

Is it acceptable for a prolog procedure to work only one way?

I have a prolog program:
link(liverpool,preston).
link(liverpool,manchester).
link(preston,lancaster).
link(preston,manchester).
link(lancaster,carlisle).
link(lancaster,leeds).
link(carlisle,leeds).
link(manchester,leeds).
%checks to see if X is in the supplied list
inlist( X, [X|_]).
inlist( X, [_|Ys]) :- inlist( X, Ys).
merge([],L,L).
merge([H|T],BList,CList):-
inlist(H,BList),
merge(T,BList,CList).
merge([H|T],BList,[H|CList]):-
merge(T,BList,CList),
not(inlist(H,BList)).
Merge works if I call it like this:
merge([a,b,c],[d,e,f],Result). --> [a,b,c,d,e,f]
or more importantly, what it was designed to solve:
merge([a,b,c],[a,d,e,f],Result). --> [a,b,c,d,e,f]
but if I call merge like this:
merge(X,[d,e,f],[a,b,c,d,e,f]).
There is a stack overflow. Is this generally acceptable behavior for a function that is designed to work one way? Or is there some convention that functions should work in both ways?
Edit: merge works if you call it like this:
merge([a,b,c],X,[a,b,c,d,e,f]). --> [d,e,f]
First, you should not call these "functions". "Predicates" is the correct term.
It's generally desirable for Prolog predicates to work "both ways". But it's not always possible or worth the effort in a particular situation.
To inform about ways a predicate is intended to be used mode-declarations can be used. These declarations conventions are different from system to system. These declarations are mostly serve as a documentation for programmers and rarely used by compilers, but can be used by testing frameworks and other helper tools.
Examples of conventions for mode declarations:
SWI-Prolog: http://www.swi-prolog.org/pldoc/man?section=modes
ECLiPSe CLP: http://eclipseclp.org/doc/applications/tutorial003.html#toc10 (scroll to 2.7.3 Mode declaration)
Also there is a convention (described in "The Craft of Prolog", for example) that input parameters of a predicate come first, output parameters come last.

Persistence of facts in Prolog

I'm kinda new in Prolog and I'm using SWI-Prolog v6.6 to storage asserts in a *.pl file.
:- dynamic fact/2.
assert(fact(fact1,fact2)).
With the code above I can make asserts and it works fine, but the problem is when I close SWI-Prolog and I open the *.pl file again, the asserts I've made are gone...
Is there a way to make asserts and those get stored even if I exit the Prolog process?
Sorry about my bad english and Thanks! (:
Saving state has certain limitations, also see the recent discussion on the SWI-Prolog mailing list.
I think the easiest way to persistently store facts on SWI-Prolog is to use the persistency library. For that I would rewrite your code in the following way:
:- use_module(library(persistency)).
:- persistent fact(fact1:any, fact2:any).
:- initialization(init).
init:-
absolute_file_name('fact.db', File, [access(write)]),
db_attach(File, []).
You can now add/remove facts using assert_fact/2, retract_fact/2, and retractall_fact/2.
Upon exiting Prolog the asserted facts are automatically saved to fact.db.
Example usage:
$ swipl my_facts.pl
?- assert_fact(some(fact), some(other,fact)).
true.
?- halt.
$ swipl my_facts.pl
?- fact(X, Y).
X = some(fact),
Y = some(other, fact).
If what you're after is just to get a list of certain facts asserted with a predicate, then mbratch's suggestion will work fine. But you may also want to save the state of your program in general, in which case you can use qsave_program/2. According to the swi docs, qsave_program(+File, +Options)
Saves the current state of the program to the file File. The result is a resource archive containing a saved state that expresses all Prolog data from the running program and all user-defined resources.
Documentation here http://www.swi-prolog.org/pldoc/man?section=runtime

How to override a user predicate with a module

Say I have a module named foo (defined in foo.pl). This module does term_expansion for instance:
:- module(foo,[term_expansion/2]).
term_expansion(A,A) :-
print A.
Of course the real code does something more complicated with the terms.
Now I want to import this library in a file, say test.pl:
:- use_module(foo).
fact(a).
When using swi-prolog however, I get the following error:
ERROR: Cannot import foo:term_expansion/2 into module user: name clash
How can I resove this error?
Term-expansion predicates are usually (they are not standard) declared as multifile (and possibly dynamic) predicates. In the specific case of SWI-Prolog, the term-expansion mechanism already defines and calls definitions for the term_expansion/2 predicate in the pseudo-module user. Thus, a possible solution would be to write instead:
:- module(foo).
:- multifile(user:term_expansion/2).
:- dynamic(user:term_expansion/2).
user:term_expansion(A,A) :-
print(A).
You should only need to load the definition of this module before loading files that you want to be term-expanded.
Regarding your follow up question about why the term_expansion/2 predicate is not declared multifile by default. I can give two different interpretations to your question. I'll address both. (1) Why do you need to repeat the multifile/1 directive? The ISO Prolog standard implies that a multifile predicate should be declared multifile in all files containing clauses for it (I say implies instead of specifies as the standard talks about "Prolog text" and not files). Actually, SWI-Prolog is quite liberal here but it's good practice to repeat the directives, moreover when other systems follow the standard more closely in this regard. (2) Why must the term-expansion predicates be declared multifile (and dynamic) in the first place? That depends on the implementation. E.g. in the Logtalk implementation of the term-expansion mechanism they are neither multifile nor dynamic.

Resources