Simple Main Predicate Example in Prolog - prolog

I decided to start playing with Prolog (SWI-Prolog). I wrote a program, and now I'm trying to write a simple main predicate so that I can create a .exe and run the program from the command line. That way, I can find true/false relationships from the command line rather than from the prolog GUI. However, I am having trouble understanding what actually goes in the main predicate. Here is the program so far:
mother(tim, anna).
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
First Try:
I put all of the relationship definitions in a predicate called family_func().Then, I tried to call that function from main by typing main. into the command line. I expected to be able to start finding relationships like I did before I created the predicates, but instead, the program started with this error:
ERROR: c:/.../ancestor.pl:18:0: Syntax error: Operator expected
Here is the code:
family_func():-
mother(tim, anna).
...
parent(X,Y) :- mother(X,Y).
...
main:-
family_func().
Second Try:
I tried putting all of the definitions in the main predicate. I expected to be able to type main. and then have the program pause and wait for me to start entering clauses (almost like in Java where you run a program and it waits for user input). Instead, when I typed main., it returned false.
Question 1:
I am used to writing code in Java. So, in my mind, The first thing I tried should work. I basically defined local variables in family_func() and then I called smaller "methods" (i.e. parent(X,Y) :- mother(X,Y).) that should find the relationships between those variables. When I call main, at the very least, I would have expected the program to wait for me to enter the relationship, return the result, and then close. Why doesn't this work?
Question 2:
How would I actually write a main predicate? Are there any good examples for a program like this? I've tried the example here, but couldn't get it to work.
Thanks for any help.
Edit:
New Attempt - main. returns false, and running parent(tim, anna). right after running main. returns false even though it should be true.
:- dynamic mother/2.
:- dynamic father/2.
family_func:-
assert(mother(tim, anna)).
assert(father(tim, bernd)).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
main:-
family_func.
Edit:
Just in case anyone else needs to know, as #CapelliC states in the comments under the answer, there needs to be a comma between calls. For example:
family_func:-
assert(mother(tim, anna)),
assert(mother(anna, fanny)),
assert(mother(daniel, fanny)),
assert(mother(celine, gertrude)),
assert(father(tim, bernd)),
assert(father(anna, ephraim)),
assert(father(daniel, ephraim)),
assert(father(celine, daniel)).

I think should be (no empty argument list allowed)
:- dynamic mother/2.
... other dynamically defined relations...
family_func:-
assert(mother(tim, anna)).
...
% rules can be dynamic as well, it depends on your application flow...
parent(X,Y) :- mother(X,Y).
...
main:-
family_func.

Related

`multifile` in combination with semweb `rdf_meta` for prefix processing in a predicate

SWI-prolog version: threaded, 64 bits, version 7.6.4
OS: Ubuntu bionic 18.04
Still working on learning prolog and ran into an interesting situation. I would like to use a predicate that is 'asserted' over multiple files (just makes the code look a little cleaner in organization), but that predicate also needs to be able to process rdf prefixes as part of the semweb package and it does not seem to work.
Here is a code block that might show the problem:
:- module(multifile1,
[
test/2
]
).
:- use_module(library(semweb/rdf_db)).
:- use_module(library(semweb/rdfs)).
:- multifile
multifile1:bar/1,
multifile1:foo/1.
:- rdf_meta
test(-, r),
foo(r).
test(bar, X) :-
bar(X).
test(foo, X) :-
foo(X).
multifile1:bar(abc) :-
format('bar: abc~n', []).
foo(rdf:about) :-
format('foo: rdf:about~n', []).
And asserting the same foo in another file:
:- module(multifile2,
[
]
).
:- use_module(library(semweb/rdf_db)).
:- use_module(library(semweb/rdfs)).
:- multifile
multifile1:foo/1.
:- rdf_meta
multifile1:foo(r).
multifile1:foo(rdf:type) :-
format('rdf:type~n', []).
In this form calling test(foo, rdf:about) works, but asserting test(foo, rdf:type) does not work. Is rdf_meta and multifile not supposed to work together or there is a bug in this code?
PS: I had added the multifile bar to make sure that works over multiple files.
I think I figured out. multifile and rdf_meta do work together. The bug in the code was related to the fact that I had defined foo in rdf_meta as foo(r). I think that expansion was causing confusion at compile time with regards to pattern match. Changing the definition to foo(-) fixed the problem. Hope this helps someone in the future.

Prolog Start clauses only after input

Is anyone aware of a built-in or any other way that will only make prolog go to the next clause when input from the terminal is given?
So for instance, the one giving the query will have to hit the y button
to go the next clause after the query has been matched.
This is the so-called vanilla meta-interpreter (I cribbed from this answer by Jan Burse):
solve(true) :- !.
solve((A,B)) :- !, solve(A), solve(B).
solve(H) :- clause(H,B), solve(B).
You can extend this to await some input by adding a predicate to ask for input before continuing:
confirm :- write('Continue? [y/n] '), flush_output, get_char(y).
Now replace the second clause with this:
solve((A,B)) :- !, solve(A), confirm, solve(B).
Edit: I asked how to add built-ins and got a response that you could just add this clause:
solve(T) :- call(T).

How do you get only one output from a swi-prolog query?

How do I get only one output from a SWI-Prolog query? I have tried using cut (!) but it does not seem to work.
For example:
I already filled my knowledge base up with statements and I wanted to find any one name who is both female and is the mother of someone.
I have already tried:
mother(X,Y), female(X).
...but that gives me all of the X-__ and Y-__
I have also tried:
mother(X,Y), female(X), !.
... but that still gives me both the X-__ and Y__
I only want to find the X. Does anyone have any tips for me to somehow only get one?
?- setof(t, Y^ ( mother(X, Y), female(Y) ), _).
which will remove duplicates (redundant answers/solutions), too. Or using library(lambda):
?- X+\ ( mother(X, Y), female(Y) ).
which does not remove redundant answers.

Writing to file (Prolog)

I've been trying to loop through a list and writing it to a file, why is the following not working?
loop_through_list(List) :-
member(Element, List),
write(Element),
write(' '),
fail.
write_list_to_file(Filename,List) :-
tell(Filename), % open file to be written
loop_through_list(List),
told. % flush buffer
First, why it fails :
You use fail to provoke backtracking, which can be a good technique, but not there. Because it will make your predicate false in the end, when member has ran out of solutions. Then, once loop_through_list is false, told isn't reached and the writing isn't made properly (when I test it, the file is created but nothing is written).
If you use :
loop_through_list([]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
instead, it works.
But, even with this code working, you might want to use
open(Filename, write, Stream), write(Stream, Element) and close(Stream) instead of tell and told for the reasons explained in the link at the bottom of this answer.
For example :
loop_through_list(_File, []) :- !.
loop_through_list(File, [Head|Tail]) :-
write(File, Head),
write(File, ' '),
loop_through_list(File, Tail).
write_list_to_file(Filename,List) :-
open(Filename, write, File),
loop_through_list(File, List),
close(File).
or
loop_through_list(File, List) :-
member(Element, List),
write(File, Element),
write(File, ' '),
fail.
write_list_to_file(Filename,List) :-
open(Filename, write, File),
\+ loop_through_list(File, List),
close(File).
using your code and joel76 trick.
See Prolog how to save file in an existing file
It covers the same matter.
I fail to see the reason to do use this method to write a list to a file.
Programming in prolog should generally not involve loops;
besides, this is not a loop structure, it's more like a hack (or even abuse).
(and just like your case leads to unexpected bugs and problems)
Just use recursion and print the elements of the list:
write_list([]).
write_list([H|T]):-
write(H),
write(' '),
write_list(T).
more elegant and could be more efficient too.
other than that, using open/4 etc (ISO IO) instead of tell/1 etc (Edinburgh IO) is generally better; check false's post
predicate loop_through_list(List), always fails, so to succed you just have to write \+loop_through_list(List),

Why does gprolog not chain together uses of modus ponens?

I am reading Learn Prolog Now, 1.1.2 Knowledge Base 2 where they write about chaining together uses of modus ponens.
The KB2.pl file:
listensToMusic(mia).
happy(yolanda).
playsAirGuitar(mia) :- listensToMusic(mia).
playsAirGuitar(yolanda) :- listensToMusic(yolanda).
listensToMusic(yolanda) :- happy(yolanda).
When the query:
playsAirGuitar(yolanda).
is submitted to gprolog, it is supposed to respond yes, because it should be able to infer it from the fact that yolanda is happy.
But gprolog responds with no. Why is that?
i think that the problem is that the clauses of the predicate listensToMusic/1 are separated.
the following code returns yes for me:
listensToMusic(mia).
listensToMusic(yolanda) :- happy(yolanda).
happy(yolanda).
playsAirGuitar(mia) :- listensToMusic(mia).
playsAirGuitar(yolanda) :- listensToMusic(yolanda).
you should get a warning like
warning: discontiguous predicate listensToMusic/1 - clause ignored

Resources