Command line argument vectors in Prolog? - prolog

Do they exist? I have written a program that solves sudoku puzzles, and it takes 3 steps to run.
> prolog
> consult(sudoku).
> solve(puzzle).
I'm looking for a way to do something like
> prolog puzzle
and be done with it. Is there a way to do this IN Prolog? Or will I have to write some helper program in C or some other language to use like
> ./solve puzzle
Any help would be appreciated. Still new to Prolog, and having trouble finding good documentation.

It depends on the Prolog system your are using. Most Prolog systems have a command line
start where one can provide an initial Prolog text to be consulted and an
initial Prolog goal to be run.
Here are some examples, I have combined the consult and run into one conjunctive goal:
SWI-Prolog:
> swipl -t ['sudoku.p'],puzzle
GNU Prolog:
> gprolog --entry-goal ['sudoku.p'],puzzle,halt
Jekejeke Prolog:
> java -jar interpreter.jar -t ['sudoku.p'],puzzle
Best Regards

Using the -g flag you can cause Prolog to execute a goal of your choice just before entering the top level. Default is a predicate which prints the welcome message. Moreover, you might like to use the -t flag that would replace the default goal prolog/0 by the one of your choice as an interactive top-level.
See also the manual.

use optparse
for example, if your program is:
main :-
opt_arguments([], _, Args),
write(Args).
and you run it like ./program 1 foo
the program will write [1,foo]

Related

How to output all solutions for Goal from non-interactive script

I have a Node.JS application that I want to do the following with:
1. Queries an API to read clauses and writes them to a file data.pro
2. Runs swipl as a command to output the result
3. Parses the result and continues the Node.JS execution.
I already have the swipl command as:
swipl -s triangular.pro -g "customRatio(A,C,D,1.05,T)." -t halt.
Now customRatio/5 has a ton of solutions that I would like to process further in my main application. An example output of running this in interactive mode would be:
A = (portugal, brazil, 656.1249261859458),
B = (brazil, germany, 5.36135535063264),
C = (germany, portugal, 0.0002993),
T = 1.0528532618885567 ;
I don't need it to be in this format, I just want the most straightforward way to get all the goals from adding something either to the command or my program. I've seen examples with findAll but couldn't get it to work with multiple outputs to the stream. I've also seen examples with dump and write.
I'm just thinking there must be a trivial way to just dump all the results to a file.
Thank you in advance.
Could your please elaborate, which problems did you encounter with forall?
The forall/2 based solution I can think is as follows (I've split it to multiple lines so it's more readable):
forall(
(Goal = customRatio(A, C, D, 1.05, T), call(Goal)),
(write(Goal), nl)
)
The command becomes:
swipl -s triangular.pro -g "forall((Goal = customRatio(A, C, D, 1.05, T), call(Goal)), (write(Goal), nl))." -t halt.
PS: you can put forall into helper predicate which takes Goal as an argument and then writes all results to screen or file, e.g.:
swipl -s triangular.pro -g "results_to_file(customRatio(A, C, D, 1.05, T))." -t halt.
So with the help of the comments from #DmitriChubarov and a similar reply from #code_x386 I got there.
Assuming we have a function that already provides the results:
customRatio(A,C,D,1.05,T)
We want all results for the Goal and write them to a file. I've done that using:
findOpportunities(MinRatio):-
open('output.txt',write, Stream),
findall((P1,P2,P3,Ratio),customRatio(P1,P2,P3, MinRatio, Ratio), List),
write(Stream, List),
close(Stream).
And then calling the following on the command line:
swipl -s triangular.pro -g "findOpportunities(1.02)." -t halt.
The solution proposed by code_x386 works but writes the clause as well as the results, for example:
customRatio((portugal,brazil,1707.3295658260913),(brazil,germany,0.03409),(germany,portugal,0.017399),1,1.0126716463779004)
customRatio((brazil,germany,0.03409),(germany,france,0.001601),(france,brazil,18663.68047779022),1,1.018628032848078)
customRatio((brazil,germany,0.03409),(germany,portugal,0.017399),(portugal,brazil,1707.3295658260913),1,1.0126716463779004)
Thank you both!

running prolog as a script

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.

I wrote some prolog logic, how do I write a script that uses it?

I'm writing an assignment for a prolog class and I'm stuck on something simple. I've written a bunch of logic in a file called question1.pl
I'm using SWI on Mac OS X, so at the command prompt I do this:
swilg
consult('question1.pl').
to load the file, then to test it I do:
?- father(homer,bart).
true
?- father(marge,bart).
false
and so on.
My question is, how do I write a "test script" for my code?
I'm assuming I should write something like question1-tests.pl that looks like this:
(write 'test1, should be true').
father(homer,bart).
(write 'test2, should be false').
father(marge,bart).
But how do I run that script?
Sorry, I know this is simple, but I'm stuck. Thanks!
Not sure if this is the best way, but you can make a script like this:
swipl <<END
[question1].
write('test1, should be true').
father(homer,bart).
write('test2, should be false').
father(marge,bart).
END
Answering my own question, I figured out I can add this to my question1.pl ...
doTests:-write('Test1, should be true'),nl,father(homer,bart).
And simply run
?- doTests
To get output. Sufficient for my assignment needs.

Writing recursion in swi-prolog

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.

How do I show the results of pattern-matching goals with several free variables in SWI-Prolog from a shell invocation?

Let's use the following prolog base :
father(anakinSkywalker, princessLeia).
father(anakinSkywalker, lukeSkywalker).
saysOhNo(lukeSkywalker).
sdesciencelover asked how to show the results of pattern-matching goals in swi-prolog from a shell invocation, and got an answer giving a manual transformation on the query, to isue a write.
swipl -q -s kb.pl -t "father(anakinSkywalker,X), writeln(X), false"
Result:
princessLeia
lukeSkywalker
This works fine when one only has a few queries with a single free variable, but manually transforming each one becomes tedious, and if we want proper output with the name of each variable along with its result, it soon becomes very annoying. For example to run the query father(AVariable, Another), one needs to write:
swipl -q -s kb.pl -t "father(AVariable,Another), write('AVariable='), write(AVariable), write(', Another='), writeln(Another), false"
Result:
AVariable=anakinSkywalker, Another=princessLeia
AVariable=anakinSkywalker, Another=lukeSkywalker
I tried to feed it the commands from a pipe, but it doesn't work great (I can't detect when it has finished writing the results, so it just hangs afterwards, and no newline separates the answers) :
(echo "father(X,Y)."; while true; do echo ";"; done) | swipl -q -s kb.pl
Result :
X = anakinSkywalker,
Y = princessLeia X = anakinSkywalker,
Y = lukeSkywalker.
swipl hangs here, and needs to be stopped with Control-C.
I know I could use a sed script to pre-process queries, adding the necessary code to print the variables in capital letters, but it would need a fair amount of work to work on complex queries, for example where two predicates must be satisfied :
father(X,Y), saysOhNo(Y).
To always give correct results, one would need to write a parser for prolog, which would be useless work since prolog already know how to do this interactively.
So here's my question : is there a way to tell GNU prolog or SWI prolog (or any other free version that can be easily installed on linux) to run some queries and print the results, just like they would do interactively, but without requiring me to type (or copy-paste) each query by hand ?
Edit : a way to store a series of queries in a file (either in the kb.pl file or an auxiliary file) and run them all, showing their results would be even better.
So far, here are the methods I found :
In gprolog
Using false's answer, I found that one must add a line at the top of the kb.pl file:
a(_) :- fail.
and then use ./query.sh kb.pl "father(X,Y), saysOhNo(Y)", where query.sh is:
#!/bin/sh
echo "a(fail)." | gprolog --query-goal "consult('$1'), $2"
When the query returns immediately (i.e. no results or a single result and gprolog managed to detect it was the last one), this will run the query consult('kb.pl'), actual_query., and then run the query a(fail). which will simply print an extraneous no on the console, thanks to the always-false predicate we added at the top of the file.
When gprolog asks what to do (i.e. several results, or a single result and gprolog couldn't detect it was the last one), this will run the query consult('kb.pl'), actual_query., read the a which asks gprolog to print all results, and then it will run the query (fail). which will simply print an extraneous no on the console, because these are just grouping parenthesis, so the query is equivalent to fail..
In xsb
One can use ./query.sh kb.pl "father(X,Y), saysOhNo(Y)", where query.sh is:
#!/bin/sh
(echo "consult('$1'), ${2%.}."; yes halt.) | xsb --noprompt --quietload --nobanner
When xsb asks what to do next, if the user types a non-empty string, followed by enter, it will print the next result, otherwise it will stop searching solutions to the current query. Therefore, with the yes halt. command, we type an infinite stream of non-empty lines. xsb will print all results to the query (each time reading halt., so as it is a non-empty string, it will continue with the next result), and return to its prompt. Then, the following halt. it receives will tell it to quit.
In swi-prolog
I haven't found a solution yet.
[rant]All this would be so much simpler, if the people building prolog implementations actually thought about using them non-interactively, like it's possible with most other languages.[/rant]
You can use the command-line option --query-goal in GNU. Like so:
$ echo a| gprolog --query-goal 'X = 1 ; X =2'
GNU Prolog 1.4.1
By Daniel Diaz
Copyright (C) 1999-2012 Daniel Diaz
| ?- X = 1 ; X =2.
X = 1 ? a
X = 2
yes
You may have found a solution for your problem but anyway, here goes my approach. You can always recurse to the bagof built-in predicate. You may read what it does in the docs, this way you will learn more about it.
swipl -q -s starwars.pl -t "bagof(X, Y^father(X,Y), BagOfFathers), bagof(Y, X^father(X,Y), BagOfChildren), writeln(BagOfFathers), writeln(BagOfChildren)."
[anakinSkywalker,anakinSkywalker]
[princessLeia,lukeSkywalker]
You can also process it later as a mapping or whatever you want, the relations are 1:1 (No sure if is the correct way of stating it but I hope you get it)
you can use the following bash script for swi-prolog:
#!/bin/sh
exec swipl -q -f none -g "load_files([interface],[silent(true)])" \
-t interface:get_args -- $*
this will load the file interface.pl and call the predicate get_args/0
to get the command line arguments you can call:
current_prolog_flag(argv, Arguments)
of course you can change the names of the predicates/files loaded.
the silent(true) arguments suppresses informational messages such as the intro text
edit:
the error message you get is cause you probably dont have an interface.pl file (neither a get_args/0 predicate).
you will have to replace interface with kb (or however you name the file) and interface:get_args with kb:father(X,Y), saysOhNo(Y) or use an auxiliary predicate within your prolog file such as run(X,Y):- father(X,Y), saysOhNo(Y) (which may be kinda cleaner)

Resources