Some problems asserting a new rule in SWI-Prolog - prolog

I am studying on Ivan Bratko book: "Programming for Artificial Intelligence" for an universitary exame and using SWI Prolog and I have some doubts about an example show on this book regarding the assert and retract predicates.
It simply present the following code that declare some facts as dynamic:
:-dynamic fast(ann).
:-dynamic slow(tom).
:-dynamic slow(pat).
Then in the Prolog shell use the assert rule to define a new rule into the database:
[debug] 59 ?- assert((faster(X,Y) :- fast(X), slow(Y))).
true.
Ok, so the new rule seems to be added to my database.
Now I try to perform this query and it fail:
[debug] 64 ?- faster(X,Y).
false.
On the book say that the output should be this one:
A = ann
B = tom
and it sound good and rational because I have consult the previous program where say that specify who is fast and who is slow and later I have add the faster rule asserting it...
Why don't work? maybe it depends by the Prolog implementation (SWI-Prolog)?

The dynamic directive in Prolog is useful in compiled programs (and normally used within a source file to be compiled). If you use assert or an equivalent mechanism to create facts (or rules) in the interactive shell, then SWI-Prolog will already assume those predicates are dynamic.
However the dynamic directive is beneficial in a case where you want to refer to a predicate through a clause in a rule before defining any facts for that predicate. That is, suppose we first do this:
?- assert((faster(X,Y) :- fast(X), slow(Y))).
true.
and then try a query:
?- faster(X,Y).
You might expect this to simply fail, because no facts exist (yet) for fast/1 or slow/1. But actually SWI-Prolog will (by design) throw an error exception:
ERROR: faster/2: Undefined procedure: fast/1
To prevent this we should add the dynamic directives in user entry mode:
?- [user].
|: :-dynamic fast/1, slow/1.
|: (type Ctrl-z to exit user entry mode)
% user://1 compiled 0.00 sec, 1 clauses
Now we will get the expected fail behavior (assuming the previously asserted rule):
?- faster(X,Y).
false.
and you can use the same mode to create your facts:
?- [user].
|: fast(ann).
|: slow(tom).
|: slow(pat).
|: (type Ctrl-z to exit user entry mode)
% user://2 compiled 0.00 sec, 4 clauses
true.
Now the faster query succeeds in two different ways:
?- faster(X,Y).
X = ann,
Y = tom ;
X = ann,
Y = pat.

Related

Prolog - How to set timestamp as an argument in a predicate?

Is there any way to use get_time(T) [which is built-in function] as an argument when I assert new facts to DB?
(I just want to compare between facts assertion time).
Code:
:- dynamic start/2.
start_interval(A) :- start(A, _), !, false.
start_interval(A) :- assert(start(A, get_time(T))).
Run Example:
Warning: c:/users/*****/desktop/prolog/4.pl:6:
Warning: Singleton variables: [T]
Welcome to SWI-Prolog (threaded, 64 bits, version 8.2.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. For legal details.
For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- start_interval(1).
true.
?- start_interval(2).
true.
?- listing(start).
:- dynamic start/2.
start(1, get_time(_)).
start(2, get_time(_)).
true.
?- get_time(T).
T = 1598718310.038124.
Instead of "start(#, get_time(_))", I would like to get to timestamp, which was made when I called start_interval(Num) at first.
(You can see also the output of get_time(T) when I call it)
Is it possible?
Maybe there is another way to compare between facts assertion time?
You just have to actually call (whatever is behind) the get_time(T) expression (nominally a predicate, but not really, as its behaviour depends on the exact moment at which it is called. Very non-logical: we are in the real of I/O).
As you write it, it remains an un-called syntactic element, standing literally for itself.
(Also, use assertz/1 in preference to the oldish assert/1):
So:
:- dynamic start/2.
start_interval(A) :- start(A, _), !, false.
start_interval(A) :- get_time(T), assertz(start(A, T)).
Then:
?- start_interval(1).
true.
?- start(A,T).
A = 1,
T = 1598726506.9420764.

How to get a listing of a specific knowledge base?

Suppose that the file foobar.pl in the current working
directory contains the following minimal knowledgebase:
foo(bar).
foo(baz).
frobozz.
If I start swi-prolog (by running swipl at the command), and immediately run
?- [foobar].
% foobar compiled 0.00 sec, 4 clauses
true.
?- listing.
...the contents of foobar are lost in a sea of >100 lines of unrelated output.
How can I limit listing's output to foobar?
Alternatively, how can I limit it to contents of those knowledgebases I have explicitly consulted?
I did look at the docs for listing/1 and listing/0, but I could not find anything helpful:
listing/1
List predicates specified by Pred. Pred may be a predicate name (atom), which lists all predicates with this name, regardless of their arity. It can also be a predicate indicator (/ or //), possibly qualified with a module. For example: ?- listing(lists:member/2)..
A listing is produced by enumerating the clauses of the predicate using clause/2 and printing each clause using portray_clause/1. This implies that the variable names are generated (A, B, ... ) and the layout is defined by rules in portray_clause/1.
listing/0
List all predicates from the calling module using listing/1. For example, ?- listing. lists clauses in the default user module and ?- lists:listing. lists the clauses in the module lists.
Of course, I did try the following useless idea:
?- foobar:listing.
true.
in SWI-Prolog, you can limit the scope of the loaded clauses with the module/2 directive. I.e. your file foobar.pl should become (for instance)
:- module(foobar, [foo/1]).
foo(bar).
foo(baz).
frobozz.
You can load the contents of a plain Prolog file into a module easily. For example:
?- fb:consult(foobar).
true
And then call:
?- fb:listing.
foo(bar).
foo(baz).
frobozz.
true.
Or list just a specific predicate:
?- fb:listing(foo/1).
foo(bar).
foo(baz).
true.

How can I ask questions on a family tree in Prolog?

I'm currently trying to learn how to use Prolog. I have SWI-Prolog version 6.2.6 installed.
It seems to run:
?- 3<4.
true.
?- 4<3.
false.
As a first example, I was trying to implement the possibility of asking questions about a family tree. So I've started with this, stored in family.pl:
father(bob,danna).
father(bob,fabienne).
father(bob,gabrielle).
mother(alice,danna).
mother(alice,fabienne).
mother(alice,gabrielle).
father(charlie,ida).
father(charlie,jake).
mother(danna,ida).
mother(danna,jake).
father(edgar,kahlan).
mother(fabienne,kahlan).
father(hager,luci).
mother(gabrielle,luci).
male(X) :- father(X,_).
female(X) :- mother(X,_).
But when I try to load this with consult(family). I get:
?- consult(family).
Warning: /home/moose/Desktop/family.pl:7:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:9:
Clauses of mother/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:11:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:12:
Clauses of mother/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:13:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:14:
Clauses of mother/2 are not together in the source-file
% family compiled 0.00 sec, 17 clauses
true.
I don't understand what is the problem here. I've found some results that mentioned that - cannot be used in identifiers, but I didn't use - in an identifier.
Question 1: What causes the Warning from above? How can I fix it?
But there are only warnings, so I've continued with
?- female(fabienne).
true.
?- male(fabienne).
false.
Ok, this seems to work as expected.
Then I've added
male(jake).
female(ida).
female(kahlan).
female(luci).
brother(X,Y):-
male(X),
(mother(Z,X)=mother(Z,Y);father(Z,X)=father(Z,Y)).
and tried:
?- brother(jake,ida).
false.
Why isn't this true?
Question 2: What is the problem with my brother rule?
Your first question is answered here.
As for the second, you're thinking in terms of functions instead of relations.
mother(Z,X) = mother(Z,Y)
is the same as saying X = Y because it compares two terms, without interpreting them. If you want Z to be the mother of both X and Y, you need a conjunction:
mother(Z, X), mother(Z, Y)
the warrning can be fixed if you move all the father and mother declarations together (do not mix them)
In brother definition you use = and you should use a logical AND so use ,(comma)
also you need to tell prolog that jake is a male because he can't figure it out from those rules
I split the brother definition in 2 because is more clear and this is like a logical OR (the first definition is valid or the second one)
father(bob,danna).
father(bob,fabienne).
father(bob,gabrielle).
father(charlie,ida).
father(charlie,jake).
father(edgar,kahlan).
father(hager,luci).
mother(alice,danna).
mother(alice,fabienne).
mother(alice,gabrielle).
mother(danna,ida).
mother(danna,jake).
mother(fabienne,kahlan).
mother(gabrielle,luci).
male(jake).
male(X) :- father(X,_).
female(X) :- mother(X,_).
brother(X,Y):-
male(X),
mother(Z,X),mother(Z,Y).
brother(X,Y):-
male(X),
father(Z,X),father(Z,Y).
For test run
brother(X,Y).
for more results you need to add who is male opr female for those childs like I did for jake

How do I add this prolog to my .pl file?

I am just starting to learn prolog. I am learning it for my CS 2300 class. I am trying to learn the basics right now. How do I add a predicate to my .pl file? I am just trying to add a predicate to my .pl file. I am doing this:
married(X,Y) :- married(Y,X).
And I get the errors:
ERROR: Undefined procedure: (:-)/2
ERROR: Rules must be loaded from a file
ERROR: See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.tx
Am I supposed to enable this somehow?
This is the given .pl file:
% File FAMILY.PL
% Part of a family tree expressed in Prolog
% In father/2, mother/2, and parent/2,
% first arg. is parent and second arg. is child.
father(michael,cathy).
father(michael,sharon).
father(charles_gordon,michael).
father(charles_gordon,julie).
father(charles,charles_gordon).
father(jim,melody).
father(jim,crystal).
father(elmo,jim).
father(greg,stephanie).
father(greg,danielle).
mother(melody,cathy).
mother(melody,sharon).
mother(hazel,michael).
mother(hazel,julie).
mother(eleanor,melody).
mother(eleanor,crystal).
mother(crystal,stephanie).
mother(crystal,danielle).
parent(X,Y) :- father(X,Y).
parent(X,Y) :- mother(X,Y).
you have to write what are predicates by using word predicates before all predicates.
predicates , clauses are keyword in prolog. you have to use that key word as well.
you can refer this link for family relation program.
http://www.dailyfreecode.com/Code/prolog-find-relations-family-3025.aspx
if you are new to prolog.
predicates
father (symbol,symbol).
clauses
father(michael,cathy).
try this code.
What's happened here is you're trying to enter rules at a query prompt. This is what you're experiencing:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.2.6)
Copyright (c) 1990-2012 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).
?- parent(X,Y) :- father(X,Y).
ERROR: Undefined procedure: (:-)/2
ERROR: Rules must be loaded from a file
ERROR: See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.txt
?-
Notice that I have the exact same error message there as you do. Prolog distinguishes between queries and consulting database. What you want to do is consult. Put all your stuff into a file and name it family.pl, and then do this:
?- [family].
You should see this result:
% family compiled 0.00 sec, 21 clauses
true.
?-
If you want to enter rules and facts interactively, consult "user" like so:
?- [user].
|: foo(X) :- bar(X).
|: <Ctrl-D>
% user://1 compiled 0.00 sec, 2 clauses
true.
Notice that the <Ctrl-D> there is typing D while holding the Control key down, not literally typing that text.
As for the other answer, it pertains to Visual Prolog only, and therefore has nothing to do with your problem. Many Prologs implement the ISO standard and you can expect them to behave similarly or identically depending on the input. SWI and GNU are some of the more popular ISO Prolog implementations. However, Visual Prolog is a completely different language and should not be called "Prolog" in passing.

how can I add the rule to this program?

Suppose you have the following program loaded in prolog:
?- listing.
fast(ann).
slow(bob).
slow(norm).
true.
?-
How can I add the following rule to this program?
faster(X,Y) :- fast(X), slow(Y).
Can some one help me write it?
There are two options.
Put the rule in a file, say faster.pl, then load that file with [faster].
Issue [user]. at the prompt, then type the rule and issue EOF (Ctrl+D in SWI-Prolog).
Prolog database is dynamic: modification to rules' base can be accomplished with assertz/1 and retract/1. Then, adding to #larsman answer, you could write
?- assertz((faster(X,Y) :- fast(X), slow(Y))).
After that, from your facts base:
?- faster(X,Y).
X = ann,
Y = bob ;
X = ann,
Y = norm.

Resources