Accessing SWI-Prolog libraries from Logtalk - prolog

I'm having a lot of fun using Logtalk, but ran into an issue using phrase_from_file. Specifically, my case looks something like this:
:- object(scan_parser).
:- public(scanlist//1).
scanlist([Scan|Scans]) --> scan(Scan), dcg_basics:blanks, scanlist(Scans).
scanlist([]) --> [].
:- public(scan_file/2).
:- mode(scan_file(+filename, -scans), one).
scan_file(Filename, Scans) :- pio:phrase_from_file(scanlist(Scans), Filename).
...
:- end_object.
The trouble is all in that call to phrase_from_file. It's unable to find scanlist, presumably because it is local to this object, so I get this error:
?- scan_parser::scan_file('input.txt', Scans).
ERROR: phrase/3: Undefined procedure: pio:scanlist/3
But, if I try to aggrandize it with a module reference like so:
scan_file(Filename, Scans) :- pio:phrase_from_file(::scanlist(Scans), Filename).
I get this error:
?- scan_parser::scan_file('input.txt', Scans).
ERROR: phrase/3: Undefined procedure: pio: (::)/3
Same if I use pio:phrase_from_file(this::scanlist(Scans), Filename) or pio:phrase_from_file(scan_parser::scanlist(Scans), Filename). If I use a single colon instead in emulation of SWI's module facility, I get messages like ERROR: phrase/3: Undefined procedure: scan_parser:scanlist/3.
I assume that the problem here is that SWI's PIO library is trying to construct something to hand to phrase and it's just not intelligent enough. But this is something that comes up for me a lot, using phrase_from_file/2, and I'm sure there will be other times I want to excavate something from SWI's library and borrow it. What's the right way forward? I'd like to preserve the encapsulation of Logtalk as much as possible.
Thanks!

I'm designing a general solution for Logtalk 3.x to support Prolog module meta-predicates that take closures as meta-arguments. Meanwhile, can you try the following (ugly) workaround:
% ensure the module is loaded
:- use_module(library(pio)).
:- object(scan_parser).
% override the non-standard meta-arguments declarations
:- meta_predicate(pio:phrase_from_file(2,*)).
:- public(scanlist//1).
scanlist([Scan|Scans]) --> scan(Scan), dcg_basics:blanks, scanlist(Scans).
scanlist([]) --> [].
:- public(scan_file/2).
:- mode(scan_file(+filename, -scans), one).
scan_file(Filename, Scans) :- pio:phrase_from_file(user:scan_parser_scanlist(Scans), Filename).
{scan_parser_scanlist(Scans, A, B)} :-
phrase(scanlist(Scans), A, B).
...
:- end_object.
I cannot test as you only posted part of the object code.

Related

How to use predicate sharing the same name from several modules in Prolog

I am new to Prolog and I'm struggling with the following problem using SWI-Prolog.
I have several files dataBase1.pl, dataBase2.pl, ... with the same structure
(based on this thread)
:- module(dataBase1,[]).
:- use_module(library(persistency)).
:- persistent
predicate1(A:any, B:any),
predicate2(A:any, B:any).
:- initialization(init).
init :-
absolute_file_name('dataBase1.db', File, [access(write)]),
db_attach(File, []).
predicate1/2, predicate2/2 are common to all the database files.
Then, I defined in a third file predicates.pl several clauses which make use of clauses in the previous databases such as testPredicate(A,B) :- predicate1(A,B), predicate2(A,B).
My problem is that I would like above clause to use predicate1/2, predicate2/2 from all the modules corresponding to database files.
In the current state, I need to precise the context module in order to use
predicate1/2, predicate2/2 (ie dataBase1:predicate1/2, dataBase2:predicate1/2,....)
I can't use use_module/1 as I will add/remove database file dynamically.
Thanks in advance for any advice !
Edit : Following the discussion in the comments, how can I define query-able predicate of the form head(X,Y) :- body() as persistent dynamic predicate ?
iirc, you should call predicates using module name as a prefix separated by colon.
http://www.swi-prolog.org/pldoc/man?section=overrule
Prolog modules don't provide a sensible solution for the design pattern you're trying to implement. This design pattern is sometimes referred as the "many worlds" pattern. But you can do it easily using in alternative Logtalk objects (you can run Logtalk with most Prolog compilers including SWI-Prolog).
First, define a root object declaring your database predicates:
:- object(database).
:- public([predicate1/2, predicate2/2]).
:- dynamic([predicate1/2, predicate2/2]).
:- end_object.
You can have any number of database objects extending this object. To associate a file with each individual database/object, you can simple use an include/1 directive to load the contents of the files into the respective objects when these are loaded. For example:
:- object(db1, extends(database)).
:- include('db1.db').
:- end_object.
:- object(db2, extends(database)).
:- include('db2.db').
:- end_object.
You can also easily create dynamic databases:
...,
% ensure the corresponding file exists
open(write, 'db42.db', Stream),
close(Stream),
% create the dynamic database object
create_object(db42, [extends(database)] [include('db42.db')], []),
...
You also want to be able to make inferences using the different databases:
Then, I defined in a third file predicates.pl several clauses which
make use of clauses in the previous databases such as
testPredicate(A,B) :- predicate1(A,B), predicate2(A,B).
You can do it easily by defining the testPredicate/2 predicate in the root object, which becomes:
:- object(database).
:- public([predicate1/2, predicate2/2]).
:- public(testPredicate/2).
testPredicate(A,B) :-
::predicate1(A,B),
::predicate2(A,B).
:- end_object.
The ::/1 is Logtalk's message to self control construct. This means that in a goal such as:
?- db1::testPredicate(A,B).
the predicate1/2 and predicate2/2 will be called in db1 while in the goal:
?- db2::testPredicate(A,B).
the predicate1/2 and predicate2/2 will be called in db2. To modify a database dynamic predicates, simply use the assert and retract messages to the database objects. For example:
?- db42::assertz(predicate1(foo,bar)).
...
Finally, you want to persist the database dynamic predicates. We can e.g add a predicate to the root object that saves all databases to the respective files. For example (assuming the database predicate clauses are facts):
:- public(save/0).
save :-
this(This),
forall(
extends_object(Database, This),
save(This)
).
save(Database) :-
atom_concat(Database, '.db', File),
open(File, write, Stream),
save_predicates(Database, Stream),
close(Stream).
save_predicates(Database, Stream) :-
current_predicate(Functor/Arity),
functor(Template, Functor, Arity),
predicate_property(Template, (dynamic)),
write_canonical(Stream, (:- dynamic(Functor/Arity))), write('.\n),
Database::clause(Template, true),
write_canonical(Stream, Template), write('.\n),
fail.
save_predicates(_, _).
To save all databases, you simply call the goal database::save. Note that the sketched solution is fully portable. you can use with any of the Logtalk supported Prolog compilers.

Prolog solve Sudoku

I'm rather new at Prolog and found this example on swi-prolog.org to solve a sudoku. But I can't run it. I looked up same_length and there is only same_length/2 not same_length/1. Also all_distinct/2 and not all_distinct/0. http://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku
Here are my errors:
ERROR: d:/.../prolog/sudoku.pl:5:10: Syntax error: Operator expected
% d:/.../prolog/sudoku compiled 0.00 sec, 0 clauses
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning:
Warning: all_distinct/1, which is referenced by
Warning: d:/.../prolog/sudoku.pl:16:8: 2-nd clause of blocks/3
And here is the code of SWI-Prolog example:
use_module(library(clpfd)).
sudoku(Rows) :-
length(Rows, 9), maplist(same_length(Rows), Rows),
append(Rows, Vs),
Vs in 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct, Columns),
Rows = [As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is],
blocks(As, Bs, Cs),
blocks(Ds, Es, Fs),
blocks(Gs, Hs, Is).
blocks([], [], []).
blocks([N1,N2,N3|Ns1], [N4,N5,N6|Ns2], [N7,N8,N9|Ns3]) :-
all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]),
blocks(Ns1, Ns2, Ns3).
problem(1, [[_,_,_,_,_,_,_,_,_],
[_,_,_,_,_,3,_,8,5],
[_,_,1,_,2,_,_,_,_],
[_,_,_,5,_,7,_,_,_],
[_,_,4,_,_,_,1,_,_],
[_,9,_,_,_,_,_,_,_],
[5,_,_,_,_,_,_,7,3],
[_,_,2,_,1,_,_,_,_],
[_,_,_,_,4,_,_,_,9]]).
I hope you can help me to find my mistake.
As far as I can tell, it now already works for you. However, I would still like to take the opportunity to show a few hints that may be useful for you:
Facts vs. directives
First, why doesn't the code that you post in your answer work?
The Prolog message already gives a pretty good indication:
Warning: The predicates below are not defined. ...
...
all_distinct/1, which is referenced by
This shows that you are in fact using all_distinct/1 (not all_distinct/2!) in your code somewhere, and it is not available.
Why? Because all_distinct/1 is available in library(clpfd), and you are not importing that library!
This is a pretty common error among beginners. Take a look at the following line in your program:
use_module(library(clpfd)).
Contrary to what you may believe, this does not import the library! Why? Because, as it stands, this is simply a Prolog fact of the form use_module/1, similar to the fact:
name(bob).
which, likewise, does not name bob, but simply states that name(bob) holds.
What you want instead is to use a directive to import a library.
Directives are terms of the form :-(D), which can also be written as :- D since (:-)/1 is a prefix operator.
Hence, what you meant to write is:
:- use_module(library(clpfd)).
This is a term of the form :-(T), and will be processed as a directive when the file is loaded.
Convenience definitions
Personally, I often write small Prolog programs, and most of them use CLP(FD) constraints. At some point, I got tired of adding :- use_module(library(clpfd)). to all my programs, so I added the following definition to my ~/.emacs:
(global-set-key "\C-cl" (lambda ()
(interactive)
(insert ":- use_module(library()).")
(forward-char -3)))
When you now press C-c l, the following snippet is inserted at point:
:- use_module(library()).
and point is placed within the () so that you only have to type the actual name of the library instead of the whose :- use_module...etc. directive.
So, to use library(clpfd), I would simply type:
C-c l clpfd
After a while, I got tired of that as well, and simply added :- use_module(library(clpfd)). to my ~/.swiplrc configuration file, because almost all programs I write perform integer arithmetic, and so it makes sense for me to make CLP(FD) constraints available in all Prolog programs I write. This is also already the case in systems like GNU Prolog and B-Prolog, for example.
However, I still have kept the .emacs definition, because sometimes I need to import other libraries, and I find typing the whole :- use_module... directive too cumbersome and error-prone.

Prolog: subsets facts not working

I've never written in Prolog before. I have to provide facts so that when it runs it displays:
?- subset([a,b],[a,c,d,b]).
true.
?-include([],[a,b]).
true.
So far, I've written this:
subset([],_Y).
subset([X|T],Y):- member(X,Y),subset(T,Y).
But include doesn't work when I write include([],[a,b]). . It shows this:
ERROR: toplevel: Undefined procedure: include/2 (DWIM could not correct goal)
Any help would be appreciated. Thanks
You get the error because you didn't define the predicate include/2. Your given example looks like include/2 should be describing the same relation as subset/2. So you can either rename your definition from subset/2 to include/2 and then run the query or you can use subset/2 to define include/2:
include(X,Y) :-
subset(X,Y).
Note that in order to use member/2 you have to use library(lists). However, in some Prolog systems (e.g. SWI) this library includes a predicate subset/2 thus leading to a warning when you consult your source file:
Warning: ...
Local definition of user:subset/2 overrides weak import from lists
If you want to implement your own version of subset/2 anyway and not get this warning, you can rename your predicate or not use library(lists) and implement your version of member/2, for example:
subset([],_Y).
subset([X|T],Y) :-
element_in(X,Y),
subset(T,Y).
element_in(X,[X|_]).
element_in(X,[Y|Ys]) :-
dif(X,Y),
element_in(X,Ys).

turning off Redefined static procedure in prolog

anyone of you could tell me how to turn off "Redefined static procedure" warnings?
I red online documentation of swi-prolog and i found this predicate no_style_check(ultimate) that in principle should turn off these warnings, but when i execute this predicate
main:-
no_style_check(singleton),
no_style_check(discontiguous),
no_style_check(multiple),
require,
test_all.
i received this error
ERROR: Domain error: style_name' expected, foundmultiple'
Anyone knows an alternative way to do this or could tell me why i receive this error ?
Thanks in advance!
Prolog is a pretty loosey-goosey language, so by default it warns you when you do certain things that are not wrong per se, but tend to be a good indication that you've made a typo.
Now, suppose you write something like this:
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Then from the prompt you write this:
?- asserta(myfoo(7,9)).
ERROR: asserta/1: No permission to modify static procedure `myfoo/2'
ERROR: Defined at user://1:9
What's happening here is that you haven't told Prolog that it's OK for you to modify myfoo/2 so it is stopping you. The trick is to add a declaration:
:- dynamic myfoo/2.
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Now it will let you modify it just fine:
?- asserta(myfoo(7,9)).
true.
Now suppose you have three modules and they each advertise themselves by defining some predicate. For instance, you might have three files.
foo.pl
can_haz(foo).
bar.pl
can_haz(bar).
When you load them both you're going to get a warning:
?- [foo].
true.
?- [bar].
Warning: /home/fox/HOME/Projects/bar.pl:1:
Redefined static procedure can_haz/1
Previously defined at /home/fox/HOME/Projects/foo.pl:1
true.
And notice this:
?- can_haz(X).
X = bar.
The foo solution is gone.
The trick here is to tell Prolog that clauses of this predicate may be defined in different files. The trick is multifile:
foo.pl
:- multifile can_haz/1.
can_haz(foo).
bar.pl
:- multifile can_haz/1.
can_haz(bar).
In use:
?- [foo].
true.
?- [bar].
true.
?- can_haz(X).
X = foo ;
X = bar.
:- discontiguous does the same thing as multifile except in a single file; so you define clauses of the same predicate in different places in one file.
Again, singleton warnings are a completely different beast and I would absolutely not modify the warnings on them, they're too useful in debugging.

Editing Eliza chatbot in Prolog

I've been struggling trying to edit Eliza chatbot in Prolog. every time I try to edit something, a new error show up. Is it protected to any sort of editing?
I edited using SWI-prolog editor. The problem is that I'm trying to minimize the code without fully understanding it. I'm trying to do a simple short version of it. So, I might removed something essential perhaps! like "my_char_type" for example. The error I got is " retract/1: No permission to modify static procedure `rules/1'"
Is there any code for a smaller chatbot that I can understand?
Please help :'(
Prolog has a static store and a dynamic store. If you open up a file, say program.pl and you put some lines in it like this:
foo(tabitha).
foo(darlene).
those facts wind up in the static store. They're not a mutable part of your program (by default).
The asserta/1, assertz/1 and retract/1 and retractall/1 procedures form the basis of the dynamic store. If you are just sitting at the console you could just add some facts to the dynamic store and remove them by doing something like this:
?- asserta(baz(tabitha)).
true.
?- baz(X).
X = tabitha.
?- retract(baz(tabitha)).
true.
?- baz(X).
false.
However, if you are sitting at the prompt after loading program.pl and you try to retract foo(tabitha) you're going to get the static procedure message:
?- retract(foo(tabitha)).
ERROR: retract/1: No permission to modify static procedure `foo/1'
ERROR: Defined at /Users/fusion/program.pl:1
The reason is because the foo/1 facts were placed in the static store rather than the dynamic store, because you didn't put them there with asserta/1 or assertz/1 or declare the predicate as dynamic, like this:
:- dynamic foo/1.
So there are two ways forward:
Edit the program source directly and reload it.
Declare the rules/1 predicate dynamic as above.
Incidentally, reloading in SWI-Prolog is best done by running make. from the prompt.
I would recommend option #1 since otherwise it will be difficult to reconstruct your working program's state when you like what it is doing.
SWISH has the simplest Eliza ever, I have the old code below, used to test my Prolog interpreter.
here is an example session
1 ?- eliza.
? i am hungry
how long have you been hungry ?
? very long
please go on
? bye
Goodbye. I hope I have helped you
true.
SWI-Prolog tested version, ported from below ELIZA.IL (alas, SWISH is apparently missing IO primitive like read_line_from_codes, so it's simpler to paste the full code)
eliza :-
write('? '), read_word_list(Input), eliza(Input), !.
eliza([bye]) :-
write('Goodbye. I hope I have helped you'), nl.
eliza(Input) :-
pattern(Stimulus, Response),
match(Stimulus, Dictionary, Input),
match(Response, Dictionary, Output),
reply(Output),
!, eliza.
match([N|Pattern], Dictionary, Target) :-
integer(N), lookup(N, Dictionary, LeftTarget),
append(LeftTarget, RightTarget, Target),
match(Pattern, Dictionary, RightTarget).
match([Word | Pattern], Dictionary, [Word | Target]) :-
atom(Word), match(Pattern, Dictionary, Target).
match([], _Dictionary, []).
pattern([i,am,1],[how,long,have,you,been,1,'?']).
pattern([1,you,2,me],[what,makes,you,think,i,2,you,'?']).
pattern([i,like,1],[does,anyone,else,in,your,family,like,1,'?']).
pattern([i,feel,1],[do,you,often,feel,that,way,'?']).
pattern([1,X,2],[can,you,tell,me,more,about,your,X,'?']) :- important(X).
pattern([1],[please,go,on]).
important(father).
important(mother).
important(son).
important(sister).
important(brother).
important(daughter).
reply([Head | Tail]) :-
write(Head), write(' '), reply(Tail).
reply([]) :- nl.
lookup(Key, [(Key, Value) | _Dict], Value).
lookup(Key, [(Key1, _Val1) | Dictionary], Value) :-
Key \= Key1, lookup(Key, Dictionary, Value).
read_word_list(Ws) :-
read_line_to_codes(user_input, Cs),
atom_codes(A, Cs),
tokenize_atom(A, Ws).
Older code: eliza and rwl

Resources