Creating a Prolog predicate via macro-like meta programming - prolog

I need a way for this to work:
?- create_pred(f, [A, B], (write(That), write(B), write(A), write(This))).
true.
?- f(this, a, b).
_L154bathis
true.
I have it working without the This so far:
?- create_pred(f, [A, B], (write(That), write(B), write(A))).
true.
?- f(a, b).
_L154ba
true.
The code for that is the following:
create_pred(Name, Args, Body) :-
length(Args, Argc),
functor(F, Name, Argc),
term_variables(F, Vars),
term_variables(Args, Vars),
assertz((F :- Body)).
Any idea how I could get that first argument unified with the This (and not the That) variable from the body?

Related

Is there a non-unifying alternative to member/2 in SWI-Prolog?

In prolog, the difference between A = B and A == B is that = tries to unify A with B, while == will only succeed if A and B are already unified.
member/2 does seem to perform unification.
Example session:
?- A = B.
A = B.
?- A == B.
false.
?- member(A, [B]).
A = B.
I have been looking but I can't find a non-unifying alternative to member/2, but not found anything. Is there something built in or do I have to invent my own thing? As I'm rather new to Prolog I don't trust myself with writing a performant version of this.
EDIT:
I came up with the following, though I don't know if the cut is correct. Without it, it seems to deliver two answers for that branch of the code (true, followed by false) though. I'd also still like to know if there is a standard library function for this.
member_eq(_, []) :-
false.
member_eq(X, [H|_]) :-
X == H,
!.
member_eq(X, [_|T]) :-
member_eq(X, T).
You may slightly modify builtin predicate member/2 to use ==/2 instead of unification:
member_not_bind(X, [H|T]) :-
member_not_bind_(T, X, H).
member_not_bind_(_, X, Y):- X==Y.
member_not_bind_([H|T], X, _) :-
member_not_bind_(T, X, H).
Sample run:
?- L=[a,b,c(E)], member_not_bind(A, L).
false.
?- A=c(E),L=[a,b,c(E)], member_not_bind(A, L).
A = c(E),
L = [a, b, c(E)].
I leave this here as it solves a related question (checking if X may unify with any item in L without actually performing the bindings)
You can use double negation like this:
member_not_bind(X, L):- \+(\+(member(X, L))).
Sample runs:
?- A=c(e),L=[a,b,c(E)], member_not_bind(A, L).
A = c(e),
L = [a, b, c(E)].
?- A=d(E),L=[a,b,c(E)], member_not_bind(A, L).
false.

Prolog: find and put into the list duplicates

Good day, guys. Can't figure out, why prolog predicate is putting all duplicates into my new list. F.e. I have to pick all duplicates:
?- duplicates([a, b, a, a, d, d], R).
R = [a, d]
I have wrote this prolog program:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
not(member(First, Rest)),
duplicates(Rest, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest).
But it returns:
R = [a, a] .
I think I need to put a (!) sign somewhere, but cannot understand, where. Any suggestions?
library(aggregate) allows a compact solution for your problem.
duplicates(L,D) :- findall(K,(aggregate(count,member(K,L),C),C>1),D).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d].
Clearly, it's less immediate to grasp than #Raubsauger' good answer, and not available in every Prolog out there.
Try this:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
\+ member(First, Rest),
duplicates(Rest, NewRest).
duplicates([First|Rest], NewRest) :-
duplicates(Rest, NewRest),
member(First, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest),
\+ member(First, NewRest).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d] ;
false.
I have choosen a version where you don't need cuts (the !). Also I added another rule: elements in NewRest can appear only once. Note: membership in NewRest can be testet only after unification of all of its entries.

Prolog reasoning about predicates

Assume someone wrote the following huge list of clauses:
loves(me, wife).
loves(me, dog).
loves(wife, dog).
hates(me, enemy).
attracts(iron, magnet).
...
Now I want to automatically generate reciprocal clauses given some higher-order predicate and rule similar to:
reciprocal([loves, hates, attracts, ...]).
some_conclusion :- some_premises.
so that I have the following expected result:
?- loves(wife, me).
true.
To keep things simple, I ignored the list argument and instead defined the simple clause reciprocal(loves). with some complex rule using reciprocal(X), but I can't seem to assert a rule with success.
I've tried different variations and orderings of
assert(
Y :- (reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X))
).
or (to add the deduced clauses themselves)
assert(Y), reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X)
but I've only got false or errors like Arguments are not sufficiently instantiated using SWI-Prolog.
My question is (obviously): how can I make this rule work? I don't care whether the rule is part of the database or just a preprocessor to add the actual clauses to the database (although the former would be preferable), I just want to learn how to reason about predicates (i.e. how to use higher-order predicates).
Note: I've learned logic programming since a month only, and I want to try out some ideas from Notation3 and N-triples etc.
EDIT:
The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to
Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).
If anyone has some solution for this one, please post it!
I found the way to add clauses one by one to the database as such (MVP):
?- [user].
|: loves(me, wife).
|: loves(me, dog).
|: loves(wife, dog).
|: reciprocal(loves).
|: (Ctrl-Z)
?- dynamic loves/2 %! seems necessary for next clause...
true.
?- reciprocal(P), X =.. [P, A, B], Y =.. [P, B, A], assert(X :- (Y, !)).
P = loves,
X = loves(A, B),
Y = loves(B, A).
?- loves(wife, me).
true.
It seems I didn't arrange the 'rule' in this way which is procedurally sound.
Now I'll focus on findall to avoid requiring user input (the ; after each solution for P).
EDIT:
I completed all but one feature... Given a file db.pl containing
loves(me, wife).
loves(me, dog).
loves(wife, dog).
attracts(iron, magnets).
and a file rules.pl containing
reciprocal([
loves,
attracts
]).
parse_reciprocal([]).
parse_reciprocal([H|T]) :-
X =.. [H, A, B], Y =.. [H, B, A], dynamic(H/2), assert(X :- (Y, !)),
parse_reciprocal(T).
:- initialization reciprocal(L), parse_reciprocal(L).
I succeed at my first goal
?- [db].
true.
?- [rules].
true.
?- loves(dog, wife).
true.
?- attracts(magnets, iron).
true.
The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to
Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).

Prolog: how can I change the output of combinations(N, [H|T], P) to return a list of pairs, rather than just the first one before ;?

Prolog: How can I change the output of combinations(N, [H|T], P) to return a list of pairs, rather than just the first one before ; ? The program works well as long as I press ; in the command line, but I want to return directly a list of pairs.
comb(1, [H|_], [H]).
comb(N, [H|T], [H|C]) :- N1 is N - 1, N1 > 0, comb(N1, T, C).
comb(N, [_|T], C):- comb(N, T, C).
This is my program. Thank you very much!
You are looking for findall/3.
findall(+Template, :Goal, -Bag)
Create a list of the instantiations Template gets successively on backtracking over Goal and unify the result with Bag. Succeeds with an empty list if Goal has no solutions. findall/3 is equivalent to bagof/3 with all free variables bound with the existential operator (^), except that bagof/3 fails when Goal has no solutions.
Example:
?- findall(X, comb(2, [a,b,c,d], X), Xs).
Xs = [[a, b], [a, c], [a, d], [b, c], [b, d], [c, d]].

Use findall with arg

I'm learning Prolog and I try to rewrite the univ predicate:
?- foo(hello, X) =.. List.
List = [foo, hello, X]
?- Term =.. [baz, foo(1)].
Term = baz(foo(1))
I already wrote a first version that works well:
get_args(_, Arity, Arity, []).
get_args(T, Arity, N, [Arg|Args]) :-
I is N + 1,
arg(I, T, Arg),
get_args(T, Arity, I, Args).
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
get_args(T, Arity, 0, Args),
!
I wanted to try another way to implement it. So, I rewrite this one by using findall and arg:
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
findall(Arg, arg(_, T, Arg), Args),
!.
This one doesn't work well. Here is an example:
?- univ(a(C, D, E), L).
L = [a, _G1312, _G1315, _G1318].
?- univ(T, [a, C, D, E]).
T = a(_G1325, _G1326, _G1327).
Thus, I have a simple question: is it possible to use arg with findall in order to retrieve the name of each arguments?
As noted by #mat, findall/3 copies variables. You can use bagof/3 instead:
univ(T, [Functor|Args]) :-
length(Args, Arity),
functor(T, Functor, Arity),
bagof(Arg, I^arg(I, T, Arg), Args),
!.
?- univ(a(C, D, E), L).
L = [a, C, D, E].
This different behaviour wrt findall/3 and setof/3 can also be useful when you need to handle attributed variables.

Resources