I am learning prolog and I am reading a book called Programming Prolog for Artificial Intelligence. As practice I want to learn how to extend one of the examples in this book. Can someone please help?
Say you have these facts:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
How would I write a prolog predicate that would give me a list of bobs parents? For example:
list_parents(bob, L).
L = [pam, george] ;
L = [george, pam] ;
true.
An all-solutions predicate like findall/3 might do the trick:
list_parents(P, L) :-
findall(Parent, parent(Parent, P), L).
Simply put, findall/3 finds all bindings for Parent in the 'backtrack-able' goal parent(Parent, P), and puts all bindings of Parent into the list L. Note that this won't remove duplicates, but you can do a sort/2 to L before returning it to create a set. Executing this:
?- list_parents(bob, L).
L = [pam, george].
If you don't have findall/3 in your PROLOG implementation, you could do it manually like this:
list_parents(P, L) :-
list_parents(P, [], L).
list_parents(P, Acc, L) :-
parent(Parent, P),
\+ member(Parent, Acc), !,
list_parents(P, [Parent|Acc], L).
list_parents(_, L, L).
This version sends calls to list_parents/2 off to an accumulator-version, list_parents/3. The latter tries to collect Parent bindings also, as long as we haven't seen them before (hence the \+ member check), and returns the list where no new Parent bindings accumulated into the Acc list can be found. Executing this gives us the same result as the first option:
?- list_parents(bob, L).
L = [pam, george].
Try this:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
list_parents(A, Es, [X|Xs]) :- parent(X, A), \+ member(X, Es), list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).
That was an inefficient method, a better method will need a "solutions" higher-order predicate.
list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)
Related
I want to add in the DB a constant and a linked variable:
?- assertz(my(x, A))
So that in the future I can define A and get the only one entry. Sth like that:
?- assertz(my(x, A)), ..., A = 2.
?- my(A, B).
A = x,
B = 2.
Can this be done?
As I noted in the comments your idea of a link like a pointer is not the way to approach solving your problem.
A common solution is to walk the tree and construct a new tree as you walk the tree by replacing the leaf of the tree with a new leaf that contains the value from the input tree along with the associated value, what you are thinking should be linked.
Since you are somewhat new to Prolog I will do this with two examples. The first will just walk a tree and only return true when successfully walked. It can be used to understand how to walk a tree and run with gtrace to single step the code to understand it.
The second example will expand on the tree walk and add the type (link as you think) to the leaf item. The the old leaf for something simple like an atom a, will become a new leaf in the tree like (a,atom).
Also this was quickly written as a demonstration only. I am sure it will have problems if pressed into doing anything more than the single example.
:- module(example,
[
example/1
]).
example(walk) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
walk(Term).
example(infer_type) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
infer_type(Term,Is),
write(Is).
walk([]) :- !.
walk([T]) :- var(T), !.
walk(L) :- is_list(L), !, L = [H|T], walk(H), walk(T).
walk(T) :- compound(T), !, T =.. [_|Args], !, walk(Args).
walk(T) :- integer(T), !.
walk(T) :- var(T), !.
walk(T) :- atomic(T), !.
walk(T) :- T =.. [Arg|Args], !, walk(Arg), walk(Args).
infer_type([],[]) :- !.
infer_type([T],[(T,var)]) :- var(T), !.
infer_type(L,S) :- is_list(L), !, L = [H|T], infer_type(H,I), infer_type(T,Is), S = [I|Is].
infer_type(T,S) :- compound(T), !, T =.. [F|Args], !, infer_type(Args,Is), S =.. [F|Is].
infer_type(T,(T,integer)) :- integer(T), !.
infer_type(T,(T,var)) :- var(T), !.
infer_type(T,(T,atom)) :- atomic(T), !.
infer_type(T,S) :- T =.. [Arg|Args], !, infer_type(Arg,I), infer_type(Args,Is), S =.. [I|Is].
Example run
Note: I know there are warnings; it is a demo not production code.
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3)
?- working_directory(_,'C:/Users/Groot').
true.
?- [example].
Warning: c:/users/Groot/example.pl:20:
Warning: Singleton variables: [T]
Warning: c:/users/Groot/example.pl:24:
Warning: Singleton variables: [T]
true.
?- example(walk).
true.
?- example(infer_type).
term_size(a((1,integer),(Hello,atom),(Atom,atom),(1,integer)+(2,integer),[(a,atom),(($),atom),(_25642,var)]))
true.
As an exercise I did not identify the string as a string, the change should be easy.
Prolog predicate next(X, List,List1), that returns in List1 the next element(s) from List that follows X, e.g., next(a,[a,b,c,a,d],List1), will return List1=[b,d].
I have tried following:
next(X, [X,Y|List], [Y|List1]) :- % X is the head of the list
next(X, [Y|List], List1).
next(X, [Y|List], List1) :- % X is not the head of the list
X \== Y,
next(X, List, List1).
next(_,[], []).
First, whenever possible, use prolog-dif for expressing term inequality!
Second, the question you asked is vague about corner cases: In particular, it is not clear how next(E,Xs,Ys) should behave if there are multiple neighboring Es in Xs or if Xs ends with E.
That being said, here's my shot at your problem:
next(E,Xs,Ys) :-
list_item_nexts(Xs,E,Ys).
list_item_nexts([],_,[]).
list_item_nexts([E],E,[]).
list_item_nexts([I|Xs],E,Ys) :-
dif(E,I),
list_item_nexts(Xs,E,Ys).
list_item_nexts([E,X|Xs],E,[X|Ys]) :-
list_item_nexts(Xs,E,Ys).
Let's see some queries!
?- next(a,[a,b,c,a,d],List1).
List1 = [b,d] ;
false.
?- next(a,[a,a,b,c,a,d],List1).
List1 = [a,d] ;
false.
?- next(a,[a,a,b,c,a,d,a],List1).
List1 = [a,d] ;
false.
Note that above queries succeed, but leave behind useless choicepoints.
This inefficiency can be dealt with, but I suggest figuring out more complete specs first:)
This version is deterministic for the cases given by #repeat using if_/3 and (=)/3. It shows how purity and efficiency can coexist in one and the same Prolog program.
next(E, Xs, Ys) :-
xs_e_(Xs, E, Ys).
xs_e_([], _E, []).
xs_e_([X|Xs], E, Ys) :-
if_(X = E, xs_e_xys(Xs, E, Ys), xs_e_(Xs, E, Ys)).
xs_e_xys([], _E, []).
xs_e_xys([X|Xs], E, [X|Ys]) :-
xs_e_(Xs, E, Ys).
%xs_e_xys([X|Xs], E, [X|Ys]) :- % alternate interpretation
% xs_e_([X|Xs], E, Ys).
I want to create a list from facts like:
table(mickel).
table(harris).
table(wolfgang).
table(yanis).
table(antti).
table(peter).
table(jeroen).
table(johan).
table(luis).
table(eric).
But i don't want to use built-in rules or predicates,
unless i define them by myself.
The result almost is like that:
?- seats(Seats).
Seats = [yanis,antti,peter,jeroen,johan,luis,eric,michel,
harris,wolfgang]
I don't know what to do,please help.
You must create your own findall predicate, this post may help:
seats(L) :- find([], L), !.
find(Acc, Loa) :- table(Y), uList(Y, Acc, AccNew), find(AccNew, Loa).
find(Acc, Acc).
uList(X, [], [X]) :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], [H|Rtn]) :- uList(X, T, Rtn).
Consult:
?- seats(L).
L = [mickel, harris, wolfgang, yanis, antti, peter, jeroen, johan, luis|...].
ass(a).
ass(b).
ass(c).
con(c,r).
arg(A, L) :- forall(member(S, L), (ass(S), \+ con(S,A))).
If I run arg(r, [a,b]) it will work but if I run arg(r,X) it returns: ERROR out of global stack. I would like it to return [a,b]. I understand this is because L is unbounded, but how can I fix this.
In the predicate:
arg(A, L) :- forall(member(S, L), (ass(S), \+ con(S,A))).
May have a limitation in your case as described in the SWI Prolog documentation for forall/2:
If your intent is to create variable bindings, the forall/2 control
structure is inadequate. Possibly you are looking for maplist/2,
findall/3 or foreach/2.
So in this case, you may be better off with:
arg(A, L) :- findall(S, (ass(S), \+ con(S,A)), L).
Which will yield:
?- arg(r, X).
X = [a, b].
?- arg(r, [a,b]).
true.
?-
I'm interested in formulae made up from lots of conjunctions (part of a larger problem). I want to write a program that takes something like this:
:- get_params(conj(conj(a,b),c),X)
and returns a list of all the parameters of the conjunctions i.e. X=[a,b,c]. At the moment I can do
:- get_params(conj(a,b),X) to get X=[a,b]
using simple Prolog pattern matching but how would you go about doing things such as
:- get_params(conj(conj(a,b),c),X) to get X=[a,b,c]
It seems really simple but I've been struggling all day!
Since you are describing a list, consider using DCG notation:
params(conj(A,B)) --> !, params(A), params(B).
params(X) --> [X].
Example:
?- phrase(params(conj(conj(a,b),c)), Ps).
Ps = [a, b, c].
Assuming that all conj functors are binary:
get_params(X, Y, L) :-
get_params(X, L1),
get_params(Y, L2),
append(L1, L2, L).
get_params(conj(X, Y), L) :-
get_params(X, Y, L), !.
get_params(A, [A]).