So, I have some Prolog code that models variable assignments, such as in a programming language, and tries to see if they are compatible with one another. So,
assigned(X, X).
and(P, Q) :- P, Q.
or(P, Q) :- P.
or(P, Q) :- Q.
% and then we should test an expression like this:
and(assigned(X, 5), assigned(X, 6)).
So that last expression fails, since X can't be assigned to both 5 and 6.
Now, what I want to do is have this test a single expression (which can and should be hardcoded into the file), and then simply print out whether or not it's able to be satisfied. But it seems that SWIPL really wants me to run interactively. Ideally, something like this:
> ./test-assignments
false.
Surely this is possible? I'm at my wit's end on this.
There are several ways to get an SWI-Prolog program to run directly from the shell. You can look at this question and the answers:
How to run SWI-Prolog from the command line?
My personal preference now is to have a file example.pl like this:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
main :-
format('Example script~n'),
current_prolog_flag(argv, Argv),
format('Called with ~q~n', [Argv]),
halt.
main :-
halt(1).
which I then run from the command line with:
$ swipl example.pl and a few arguments
Example script
Called with [and,a,few,arguments]
The initialization directive tells the interpreter which goal to evaluate after it loads the program: here it is main/0. The name main is a convention, it could have been called anything else.
See the linked question and answers for other options.
Related
In SWI-Prolog, if I use assert and retract at the prompt, I get
?- assert(at(1)).
true.
?- retract(at(1)).
true.
However, if I put these statements into a program file called "test" as
assert(at(1)).
retract(at(1)).
and run SWI-Prolog as
> swipl
?- [test].
I get
ERROR: /....../test:2:
No permission to modify static procedure `retract/1'
true.
What does this mean and how should I deal with it?
Put statements within a predicate, e.g.:
:- dynamic at/1.
test_assert :-
assert(at(1)).
test_retract :-
retract(at(1)).
Load the program, and then run:
?- test_assert.
true.
?- at(X).
X = 1.
?- test_retract.
true.
?- at(X).
false.
The prompt and source code files are different environments with slightly different behaviours. It's like the difference between calling Python len(x) in the repl and writing function len(x): in Python source code - you would be overriding the builtin len() with your own one. Python lets you do that, SWI Prolog also does but not easily.
When you type them at the prompt, you call the existing predicate assert/1 and actually do insert the fact at(1). into the database. When you type retract/1 you actually do retract the fact at(1) from the database.
In a fresh prompt, try ?- listing(at). and get an error, then ?- assert(at(1)). then do the listing again and see the fact, then retract it and try the listing and see only the remains of the dynamic declaration and the fact is gone.
When you put them in a source code file, you would be trying to override the existing builtin predicates with your new ones. Your new ones say "assert/1 is a predicate which succeeds when its arugment unifies with at(1)" and "retract/1 is a predicate which succeeds when its arugment unifies with at(1)".
That is, they don't do any asserting or retracting or database changes.
In your test file, put this:
:- redefine_system_predicate(assert(_)).
:- redefine_system_predicate(retract(_)).
assert(at(1)) :- true.
retract(at(1)) :- true.
Then save and consult it:
?- [testing].
true.
?- listing(at). % <-- your code ran, but did not insert `at(1)`.
ERROR: procedure `at' does not exist (DWIM could not correct goal)
^ Exception: (13) setup_call_catcher_cleanup(system:true, prolog_listing:listing_(user:at, []), _19450, prolog_listing:close_sources) ? abort
% Execution Aborted
?- assert(P). % <-- it's now behaving
P = at(1). % <-- like any other predicate.
I wrote a program in prolog. If I run it like so:
>swipl program.pl
?- make.
?- my_predicate(my_arguments).
everything works perfectly.
However, if I run it like so:
>swipl program.pl
?- my_predicate(my_arguments).
It works differently. The predicate is still running, but it loops.
program.pl uses :- dynamic some_predicates/3 and :- consult(other_file).. other_file.pl uses :-include(yet_another_file).. Both other_file.pl and yet_another_file.pl use :- use_module(library(tabling))..
What does calling make. do that makes my program run correctly, and how can I fix it so that simply loading it with swipl is enough?
If I have a prolog file defining the rules, and open it in a prolog terminal in windows, it loads the facts. However, then it shows the ?- prompt for me to manually type something. How can I add code to the file, so that it will actually evaluate those specific statements as if I typed them in?
something like this
dog.pl
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
dog(X).
Does anyone know how to do this?
Thanks
There is an ISO directive on this purpose (and more): initialization
If you have a file, say dog.pl in a folder, with this content
dog(john).
dog(ben).
:- initialization forall(dog(X), writeln(X)).
when you consult the file you get
?- [dog].
john
ben
true.
Note that just asserting dog(X). doesn't call dog(X) as a query, but rather attempts to assert is as a fact or rule, which it will do and warn about a singleton variable.
Here's a way to cause the execution the way you're describing (this works for SWI Prolog, but not GNU Prolog):
foo.pl contents:
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
% This will write each successful query for dog(X)
:- forall(dog(X), (write(X), nl)).
What this does is write out the result of the dog(X) query, and then force a backtrack, via the false call, back to dog(X) which will find the next solution. This continues until there are no more dog(X) solutions which ultimately fails. The ; true ensures that true is called when dog(X) finally fails so that the entire expression succeeds after writing out all of the successful queries to dog(X).
?- [foo].
john
ben
true.
You could also encapsulate it in a predicate:
start_up :-
forall(dog(X), (write(X), nl)).
% execute this and output this right away when I open it in the console
:- start_up.
If you want to run the query and then exit, you can remove the :- start_up. from the file and run it from the command line:
$ swipl -l foo.pl -t start_up
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.2.3)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
john
ben
% halt
$
dog.pl:
dog(john).
dog(ben).
run :- dog(X), write(X).
% OR:
% :- dog(X), write(X).
% To print only the first option automatically after consulting.
Then:
$ swipl
1 ?- [dog].
% dog compiled 0.00 sec, 4 clauses
true.
2 ?- run.
john
true ; # ';' is pressed by the user
ben
true.
3 ?-
I setup the following rules to find if there is a relationship between two elements:
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).
Can I write a PrologScript that will check all these queries for a fact? Although I plan to use Ruby&Rake, someone is trying to do a non-interactive call from PHP here and it has not worked. I also saw this answer and tried Kaarel's answer. I just added a new opts_spec:
opts_spec(
[ [opt(day), type(atom),
shortflags([d]), longflags(['term', 'day']),
help('name of day')]
, [opt(goal),
shortflags([g]), longflags([goal]),
help('goal to be called')]
, [opt(projectReferences), type(atom),
shortflags([pr]), longflags(['term', 'projectReferences']),
help('Project Reference lookup')]
]
).
I then compiled with:
.\swipl.exe -o day.exe -g main -c "D:\DevProjects\AskJoe\Output\Sample.pro"
And ran it with:
./day.exe -g "day(Sunday)"
And got error:
ERROR: Prolog initialisation failed: ERROR: validate_opts_spec/1:
Domain error: unique_atom' expected, foundterm' (ambiguous flag)
My goal is to have this work:
./day.exe -g "transitiveReference('a','b')"
I don't like compiling a "day.exe" to run a script (according to the docs this often is not necessary), but I have found no other way to pass arguments to rules.
I saw a basic intro on swi-pl.org that has not helped much. It does not explain how to make the leap from the script.sh file example to the execution of ./eval 1+2. In fact, the example is a comment so I'm totally lost
Here is a very crude example of a PrologScript program that will read its arguments as a single goal (which may be compound), call it, and then terminate. It should work on *nix systems, and has been tested on OS X. It is just a slight variation of the example program given for using PrologScript in the SWI docs:
#!/usr/bin/env swipl
:- initialization main.
query :-
current_prolog_flag(argv, Argv),
concat_atom(Argv, ' ', Atom),
read_term_from_atom(Atom, Term, []),
call(Term).
main :-
catch(query, E, (print_message(error, E), fail)),
halt.
main :-
halt(1).
projectReferences(valueA, valueB) :- writeln('I was called!').
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).
After saving this file as, e.g., cli_test.pl, you'll need to change the permissions on the file so that the operating system will recognize it as an executable:
chmod -x scratchboard.pl
After that, you should be able to call the file as as a normal executable from the command line:
$ path/to/the/file/scratchboard.pl 'transitiveReferenceD1(A,D).'
I was called!
Note:
The goal to be evaluated is simply passed as a single argument. query/0 will then retrieve this argument using current_prolog_flag/2, read it as a Prolog term, and call it.
Since the program is not running in interactive mode, the only output will result from explicit imperatives to write out, such as occur if catch/3 (in the body of main/0) is triggered by an error or if projectReferences/2 is called successfully.
Using library(optparse) seems advisable for more complicated cli interface, but is not necessary for your stated aim of merely querying goals in a file.
I understand that getting the PrologScript approach to work on Windows is somewhat different. A bit of information can be fond here: http://www.swi-prolog.org/FAQ/PrologScript.html
So I got this all working and then after a few runs everything just stopped. I started getting 'permission denied bad interpreter' errors. All I can say is that it has something to do with the hashBang. The workaround for me was to create a shell script around the call to swipl:
shellscript.sh
#!/bin/bash
swipl -s script4.pl 'projectReferences(A,D).'
Then I continued using aBathologist's example, but just took off the hashBang:
:- initialization main.
query :-
current_prolog_flag(argv, Argv),
concat_atom(Argv, ' ', Atom),
read_term_from_atom(Atom, Term, []),
call(Term).
main :-
catch(query, E, (print_message(error, E), fail)),
halt.
main :-
halt(1).
projectReferences(valueA, valueB) :- writeln('I was called!').
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).
I have successfully connected PHP with Prolog and managed to query the desired knowledge base that resides in knowledge_base.pl file and managed to echo the results via php exec function.
I encountered a problem in echoing the true/false value that Prolog returns after each query execution (see previous question) so I came up with a solution that I have trouble implementing.
Let's assume I have a simple knowledge_base.pl file with these facts and rules:
girl(erin).
boy(john).
likes(erin, reading).
likes(john, reading).
hangs_out_with(erin, X) :-
likes(X, reading),
boy(X),
writeln('Someone s got a new friend!!').
Lets say that I want to see if erin is a girl and if so, write that it is true, or else write that it is false. I added this to my knowledge_base.pl file:
girl(erin) :-
girl(erin)
-> write('it is true')
; write('it is not true').
When I enter the query: ?- girl(erin). I get an out of local stack error. I searched the Web and found out that this is due to infinite recursion.
Can someone give me a hint in how to write
girl(X) :-
( girl(X)
-> write('it is true')
; write('it is not true')).
in Prolog? Thanks in advance.
As a new user I'm not allowed to post pictures.
SWI-Prolog's output:
1 ?-hangs_out_with(erin,kosta).
false.
2 ?-hangs_out_with(erin,john).
Someone s got a new friend!!
true.
Command prompt's output:
C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)
C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,john),halt.
Someone s got a new friend!!
The first query fails and the second succeds. As you can see, prolog after the query executions outputs true/false but when i execute the same query in command prompt the true/false values do not get echoed!!
I think you should ask
is_girl(X) :-
girl(X) -> write('t is true') ; write('it is not true').
EDIT
Do you mean this kind of thing ?
is_type(Type, X) :-
call(Type, X) -> writeln(yes); writeln(no).
so you "connect PHP to Prolog" by executing a Prolog query in command shell and capturing and analyzing its output. http://www.swi-prolog.org/man/quickstart.html says
"2.1.1.1 Starting SWI-Prolog on Unix
By default, SWI-Prolog is installed as 'swipl'. The command-line arguments of SWI-Prolog itself and its utility programs are documented using standard Unix man pages."
So do consult a man page about "-q" switch. Is it the "-q" for quiet perhaps? What does "-f" mean (ok, that's probably "file")? But the solution is the same - just use a different name for the new predicate.
Notice that in your first attempt,
C:>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)
halt isn't executed, precisely because hangs_out_with(erin,kosta) has failed. A comma signifies conjunction (an "and").
All you need to do is create a new predicate that reports whether the goal is true or false, and succeeds always:
report_hangs_out_with(A,B):-
hangs_out_with(A,B)- > writeln(['YES',A,B]) ; writeln('NO').
and use it instead:
C:>swipl -q -f knowledge_database.pl -g report_hangs_out_with(erin,kosta),halt.
Also, Prolog echoing "true" or "false" is part of its interactive session. But you terminate it with halt!
edit: you posted:
1 ?-hangs_out_with(erin,kosta).
false.
So, when you run that query in interactive Prolog shell, it reports the failure. halt/0 exits the Prolog shell. When you run it with a goal specified through command line switch, apparently it does not report the success of failure. That's the fact of nature as far as we users are concerned (a.o.t. the compiler writers). It is easily addressable with what I've shown you. And you yourself say that it works, too. For each predicate that can fail or succeed, define another, reporting predicate, just as I've shown you.
Here's a sample transcript (in Windows, but that's irrelevant). That should clear up your doubts:
C:\Program Files\pl\bin>plcon -q -g (writeln('****'),halt).
**** // didn't say Yes, right??
C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****'),halt.
**** // didn't say Yes here either
C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****').
****
Yes // does say Yes as part of interaction
2 ?- halt.
C:\Program Files\pl\bin>
So that's the way it is. Deal with it. :) Or write Jan and ask him to change it. :)
girl(erin) :-
girl(erin)
-> write('it is true')
; write('it is not true').
This is wrong for two reasons. Prolog tries to resolve the body taking the left-most literal.
So it basically goes in a loop "is erin girl? yes, if erin is girl. Is erin girl?..."
The second reason is you are mixing two different things. Try to keep your knowledge representation part separated from the way you use it.
In Prolog you just say:
girl(erin)
And then query
?- girl(erin)
Prolog will just say "yes". If you want to print it, probably the easiest way is adding a predicate.
check_and_print(X) :- X, write(X), write(" is true").
Probably you need a call(X) instead of X, depending on the implementation you are using.
I'm not sure about the command prompt out, I suspect the outcome is returned in a different way.