Prolog findall/3 - prolog

Say I have a predicate pred containing several facts.
pred(a, b, c).
pred(a, d, f).
pred(x, y, z).
Can I use findall/3 to get a list of all facts which can be pattern matched?
for example, if I have
pred(a, _, _)
I would like to obtain
[pred(a, b, c), pred(a, d, f)]

Just summing up what #mbratch said in the comment section:
Yes, but you have to make sure that you either use named variables or construct a simple helper predicate that does that for you:
Named variables:
findall(pred(a,X,Y),pred(a,X,Y),List).
Helper predicate:
special_findall(X,List):-findall(X,X,List).
?-special_findall(pred(a,_,_),List).
List = [pred(a, b, c), pred(a, d, f)].
Note that this doesn't work:
findall(pred(a,_,_),pred(a,_,_),List).
Because it is equivalent to
findall(pred(a,A,B),pred(a,C,D),List).
And thus doesn't unify the Variables of Template with those of Goal.

Related

Prolog Partial Matching

If there is a rule that cannot be satisfied with all parameters, is there a standard way to get a partial match with just some of the parameters?
For example, the following query can not find a solution:
?- query(A, B, C).
false.
But a solution can be found if we don't try to unify on C:
?- query_best_effort(A, B, C).
A = alfa,
B = bravo ;
I have the following code that implements this functionality. But is there a more Prolog-way to do this?
fact1(alfa).
fact2(bravo).
fact3(charlie).
rule1(A) :-
fact1(A).
rule2(B) :-
fact2(B).
rule3(C) :-
fact3(C),
C \== charlie.
query(A, B, C) :-
rule1(A),
rule2(B),
rule3(C).
query_best_effort(A, B, C) :-
query_chain3(A, B, C);
query_chain2(A, B);
query_chain1(A).
query_chain3(A, B, C) :-
query(A, B, C).
query_chain2(A, B) :-
\+query_chain3(A, B, _),
rule1(A),
rule2(B).
query_chain1(A) :-
\+query_chain2(A, _),
rule1(A).
First, a comment on programming style. When using disjunctions (;/2), always wrap them between parenthesis and avoid writing ; at the end of a line. In your case:
query_best_effort(A, B, C) :-
( query_chain3(A, B, C)
; query_chain2(A, B)
; query_chain1(A)
).
This recommended style contributes to code readability.
You can also avoid using negation (\+/1) by using instead the *->/2 soft-cut control construct implemented in several Prolog systems (a few systems, e.g. SICStus Prolog, implement it as an if/3 built-in predicate):
query_best_effort(A, B, C) :-
( query_chain3(A, B, C) *->
true
; query_chain2(A, B) *->
true
; query_chain1(A)
).
query_chain3(A, B, C) :-
query(A, B, C).
query_chain2(A, B) :-
rule1(A),
rule2(B).
query_chain1(A) :-
rule1(A).
The *->/2 control construct, unlike the standard ->/2 control construct, allows backtracking into the condition. When calling the query_best_effort/3 predicate, the query_chain2/2 predicate will only be called if there are no solutions for the query_chain3/3 goal and the query_chain1/1 predicate will only be called if there are no solutions for the query_chain3/3 and query_chain2/2 goals, which I assume was your intention with the use of disjunction and negation?
Sample call:
| ?- query_best_effort(A, B, C).
A = alfa
B = bravo
yes
Note, however, that *->/2 is, like negation, a non-logical control construct.

How to get structure name?

If I have struct_name(a, b, c, d, e)., how can I get the name of the struct? In this case, it would be struct_name.
Is there any specific command to do this or should I transform it in some way in a list (I tried and atom_chars doesn't work) and find save the characters until meeting ( ?
One solution is to use functor/3.
Example:
?- Term = struct_name(a, b, c, d, e),
functor(Term, F, Arity).
Term = struct_name(a, b, c, d, e),
F = struct_name,
Arity = 5.
Related term inspection predicates are arg/3 and (=..)/2.
The use of such predicates often indicates a problem with your data structure design, and typically severly limits the generality of your relations.
Note in particular that you can use them only if their arguments are sufficiently instantiated.
For example:
?- functor(Term, F, A).
ERROR: Arguments are not sufficiently instantiated
This means that you can no longer use such predicates for generating answers.
You can use the (=..)/2 predicate (this is an ISO-predicate, so it should work on (almost) all Prolog interpreters) that has on the left side a functor, and on the right side the name of the functor followed by its operands.
So:
?- struct_name(a, b, c, d, e) =.. L.
L = [struct_name, a, b, c, d, e].
You can thus obtain the name of the struct with:
get_name(A,N) :-
A =.. [N|_].
When you then call it with struct_name(a, b, c, d, e), it will give you:
?- get_name(struct_name(a, b, c, d, e),N).
N = struct_name.

bagof only gives one item, though multiple items fit

This code works as expected:
?- bagof(R,member(r(R),[r(a),r(b),r(c),r(d)]),Rs).
Rs = [a, b, c, d].
but a similar call, the one I really want, does not:
?- bagof(R,member(r(_,R),[r(_,a), r(_,b), r(_,c), r(_,d)]),Rs).
Rs = [a]
; gives me more answers -- but I want [a,b,c,d]. What's my fix?
bagof/3 and _ do not flock together directly. Same is true for setof/3.
So either give all those anonymous variables a name and declare them as a local variable, use an auxiliary predicate, or use library(lambda):
?- bagof(R,R+\member(r(_,R),[r(_,a), r(_,b), r(_,c), r(_,d)]),Rs).
Rs = [a,b,c,d].
You need to existentially qualify the arguments that you're not interested in instead of using anonymous variables:
?- bagof(R,A^A1^A2^A3^A4^member(r(A,R),[r(A1,a), r(A2,b), r(A3,c), r(A4,d)]),Rs).
Rs = [a, b, c, d].
This is necessary as bagof/3 (and setof/3) will return a bag (set) of solutions for each instantiation of the free variables (i.e. the variables in the goal that are not in the template). In alternative, you can use the findall/3 predicate (which ignores free variables):
?- findall(R,member(r(A,R),[r(A1,a), r(A2,b), r(A3,c), r(A4,d)]),Rs).
Rs = [a, b, c, d].
But note that findall/3 returns an empty list when there are no solutions while bagof/3 (and setof/3) fail when there are no solutions.
Another alternative to avoid a long list of existentially qualified variables in calls to bagof/3 and setof/3 is to introduce an auxiliary predicate with a single clause whose head only lists the arguments you're interested in. For example:
r(R) :-
member(r(_,R),[r(_,a), r(_,b), r(_,c), r(_,d)]).
?- bagof(R, r(R), Rs).
Rs = [a, b, c, d].
Paulo contributed library(yall), autoloaded in SWI-Prolog. Yall (Yet Another Lambda Library) solves your problem easily:
?- bagof(R, {R}/member(r(_,R),[r(_,a), r(_,b), r(_,c), r(_,d)]),Rs).
Rs = [a, b, c, d].

Split list on given element

I have a list C and I want to split the list using the element c in the list.
The expected results are as example:
?- split([a,c,a,a,c,a,a,a],X).
X = [[a],[a,a],[a,a,a]].
Can anybody help? Thanks in advance.
I can remove the c in the list now and here is my codes.
split([],[]).
split([H|T],[H|S]) :- H=a,split(T,S).
split([H|T],S) :- H=c,split(T,S).
Your "remove c" predicate would look better like this:
remove_c([c|T], S) :-
remove_c(T, S).
remove_c([a|T], [a|S]) :-
remove_c(T, S).
This still only works for lists that have only c and a in them.
If you want to "split", this means you at least need another argument, to collect the a's between the c's. For example:
split_on_c(List, Split) :-
split_on_c_1(List, Split, []).
split_on_c_1([], [Acc], Acc).
split_on_c_1([c|Rest], [Acc|Split], Acc) :-
split_on_c_1(Rest, Split, []).
split_on_c_1([a|Rest], Split, Acc) :-
split_on_c_1(Rest, Split, [a|Acc]).
Again, this expects lists of a and c only. It could also be done in different ways, but this is a start.
While learning a language you need to get accomplished to common abstractions already established (in simpler terms, use libraries). What about
split(In, Sep, [Left|Rest]) :-
append(Left, [Sep|Right], In), !, split(Right, Sep, Rest).
split(In, _Sep, [In]).
to be used like
?- split([a,c,a,a,c,a,a,a],c,R).
R = [[a], [a, a], [a, a, a]].
Use the meta-predicate splitlistIf/3 together with reified term equality
(=)/3, like this:
Here is the query the OP gave in the question:
?- splitlistIf(=(c),[a,c,a,a,c,a,a,a],Xs).
Xs = [[a],[a,a],[a,a,a]].
Note that above code is monotone, so the following query gives reasonable results:
?- splitlistIf(=(X),[Y,X,Y,Y,X,Y,Y,Y],Xs), Y = a, X = c.
X = c,
Y = a,
Xs = [[a],[a, a],[a, a, a]].

Prolog - union doesn't check for duplicates or that the list is in order

I'm trying to write a union function in Prolog and I'm running into some trouble. I have looked up examples and listed the built in example for union but I am writing my own for an assignment. I have noticed some strange results when a list has duplicate values and/or when the order of the list is not ascending.
The following is the built in union code:
union([], A, A) :- !.
union([A|C], B, D) :-
memberchk(A, B), !,
union(C, B, D).
union([A|B], C, [A|D]) :-
union(B, C, D).
I believe that the pseudocode here is that we're looking to find all of list 1 inside of our result and once it's exhausted, we compare list 2 and list 3. They should be the same. However, this does not check for order.
30 ?- union([1,2,3],[],[3,2,1]).
false.
Why is this false? List 1 and List 3 are the same set even though the order is different!
24 ?- union([a],[a,a],[a,a]).
true.
25 ?- union([a,a],[a],[a,a]).
false.
What is different between these two? They should yield the same result. However, due to the way that the function is written, in the end we just compare list 2 and list 3 which are different for line 25.
My question is. . . Is there a better way to write these functions such that duplicates are handled properly and order does not matter? One would assume that the built in methods would do the trick but no dice.
First, it's easier to read a code written with consistent naming:
union([], A, A) :- !.
union([A|B], C, D) :-
memberchk(A, B), !,
union(B, C, D).
union([A|B], C, [A|D]) :-
union(B, C, D).
What does it do? Given two lists A and B, it produces the result with a prefix of all elements of A not present in B, and then B itself. So, union([1,2,3],[],[1,2,3]). And also union([1,2,3],[2],[1,3,2]). You see that order is preserved here. So if you want to compare lists regardless of their order, you should write a special, additional predicate for that: union([1,2,3],[],X), regardless(X,[3,2,1]) should work then.
Same with the duplicates - your set equality predicate should disregard any. union as presented above OTOH is not about sets, but about lists. There are many different lists representing the same set, but as lists they are considered different.
In your 25 you hit the issue of duplicates: union([a,a],[a],X) produces X=[a]. Again, as set it is the same as [a,a], but as lists they are different.
One strategy for coping with this is to represent sets as strictly increasing lists - if your elements have order well defined for them. Then we can write union such that given two sets according to that definition, it will also produce a set, and it will work efficiently at that:
union([],X,X):-!.
union(X,[],X):-!.
union([A|B],[C|D],[H|T]):-
A #< C -> H=A, union(B,[C|D],T) ;
C #< A -> H=C, union([A|B],D,T) ;
H=A, union(B,D,T).
We will have to define make_set/2 predicate here too. Even better (in some respects) is representing sets (again, of comparable elements) by self-balancing binary trees.
you are implementing a concept using the 'tools' that the language (Prolog, in your case) put in your hands. Then you should better define (in natural language, first) what's your target, considering that also append/3 could fit the union concept.
you can call list C a union among lists A,B if....
I would fill the ellipsis this way
each A element appears once in C and
each B element appears once in C and
each C element appears in A or B
If you agree on this definition, then an implementation could be
union(A, B, C) :-
elems_once(A, [], C1),
elems_once(A, C1, C2),
each_elems(C2, A, B, C).
That is far less efficient that the library code shown, but it's the price of generality...
To have a union(?A, ?B, ?C) (that is, you can use any variable as input or output) I create a new union
uniao(?A, ?B, ?C)
that uses list:union among other stuff, as:
uniao([], [], []) :- !.
uniao(X, [], X) :- !.
uniao([], X, X) :- !.
uniao(X, Y, Z) :-
nonvar(X),
nonvar(Y),
var(Z),
list_to_set(X, Xs),
list_to_set(Y, Ys),
union(Xs, Ys, Z),
!.
uniao(X, Y, Z) :-
nonvar(X),
var(Y),
nonvar(Z),
list_to_set(X, Xs),
list_to_set(Z, Zs),
subset(Xs, Zs),
subtract(Zs, Xs, Y),
!.
uniao(X, Y, Z) :-
var(X),
nonvar(Y),
nonvar(Z),
list_to_set(Y, Ys),
list_to_set(Z, Zs),
subset(Ys, Zs),
subtract(Zs, Ys, X),
!.
uniao(X, Y, Z) :-
nonvar(X),
nonvar(Y),
nonvar(Z),
list_to_set(X, Xs),
list_to_set(Y, Ys),
list_to_set(Z, Zs),
union(Xs, Ys, Ts),
subtract(Zs, Ts, []),
subtract(Ts, Zs, []),
!.

Resources