Prolog unify Lists inside a list - prolog

I'm trying to define a relation over lists...
?- matrix_items([[a,b],[c,d],[e,f]],Rs).
Rs = [a,b,c,d,e,f]. % expected result
So far, I was able to do something like this; unfortunately it doesn't add up all the elements:
sift([],_).
sift([H|T],[H|Result]) :-
create(H,Result),
sift(H,Result).
create([],_).
create([H|T],[H|R]) :-
create(T,R).
Hope hear from you soon.

Try something like this. I've changed the name of the predicate to flatten_l as unify has other connotations in Prolog:
flatten_l([H|T], FL):-
flatten_l([H|T], [], FL).
flatten_l([], FL, FL):- !.
flatten_l([H|T], ML, FL):-
flatten_l(T, ML, NL),
!,
flatten_l(H, NL, FL).
flatten_l(X, FL, [X|FL]).
Note also that this predicate will give you a stack overflow error if the first argument is uninstantiated...

If you want to collapse all of the lists (even sub-lists), you can use flatten/2.
If you only want to collapse a single level, then the following should work:
unify([], []).
unify([X|Xs], Ret) :- unify(Xs, Rs), append(X, Rs, Ret).

If you use SWI-pl, you can call flatten/2 to flatten all levels of nesting or append/2 to flatten only one level.

Related

I have defined multiple predicates that seem to share a common form

All of these predicates are defined in pretty much the same way. The base case is defined for the empty list. For non-empty lists we unify in the head of the clause when a certain predicate holds, but do not unify if that predicate does not hold. These predicates look too similar for me to think it is a coincidence. Is there a name for this, or a defined abstraction?
intersect([],_,[]).
intersect(_,[],[]).
intersect([X|Xs],Ys,[X|Acc]) :-
member(X,Ys),
intersect(Xs,Ys,Acc).
intersect([X|Xs],Ys,Acc) :-
\+ member(X,Ys),
intersect(Xs,Ys,Acc).
without_duplicates([],[]).
without_duplicates([X|Xs],[X|Acc]) :-
\+ member(X,Acc),
without_duplicates(Xs,Acc).
without_duplicates([X|Xs],Acc) :-
member(X,Acc),
without_duplicates(Xs,Acc).
difference([],_,[]).
difference([X|Xs],Ys,[X|Acc]) :-
\+ member(X,Ys),
difference(Xs,Ys,Acc).
difference([X|Xs],Ys,Acc) :-
member(X,Ys),
difference(Xs,Ys,Acc).
delete(_,[],[]).
delete(E,[X|Xs],[X|Ans]) :-
E \= X,
delete(E,Xs,Ans).
delete(E,[X|Xs],Ans) :-
E = X,
delete(E,Xs,Ans).
There is an abstraction for "keep elements in list for which condition holds".
The names are inclide, exclude. There is a library for those in SWI-Prolog that you can use or copy. Your predicates intersect/3, difference/3, and delete/3 would look like this:
:- use_module(library(apply)).
intersect(L1, L2, L) :-
include(member_in(L1), L2, L).
difference(L1, L2, L) :-
exclude(member_in(L2), L1, L).
member_in(List, Member) :-
memberchk(Member, List).
delete(E, L1, L) :-
exclude(=(E), L1, L).
But please take a look at the implementation of include/3 and exclude/3, here:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3
Also in SWI-Prolog, in another library, there are versions of those predicates called intersection/3, subtract/3, delete/3:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#intersection/3
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#subtract/3
https://www.swi-prolog.org/pldoc/doc_for?object=delete/3
Those are similar in spirit to your solutions.
Your next predicate, without_duplicates, cannot be re-written like that with include/3 or exclude/3. Your implementation doesn't work, either. Try even something easy, like:
?- without_duplicates([a,b], L).
What happens?
But yeah, it is not the same as the others. To implement it correctly, depending on whether you need the original order or not.
If you don't need to keep the initial order, you can simply sort; this removes duplicates. Like this:
?- sort(List_with_duplicates, No_duplicates).
If you want to keep the original order, you need to pass the accumulated list to the recursive call.
without_duplicates([], []).
without_duplicates([H|T], [H|Result]) :-
without_duplicates_1(T, [H], Result).
without_duplicates_1([], _, []).
without_duplicates_1([H|T], Seen0, Result) :-
( memberchk(H, Seen0)
-> Seen = Seen0 , Result = Result0
; Seen = [H|Seen0], Result = [H|Result0]
),
without_duplicates_1(T, Seen, Result0).
You could get rid of one argument if you use a DCG:
without_duplicates([], []).
without_duplicates([H|T], [H|No_duplicates]) :-
phrase(no_dups(T, [H]), No_duplicates).
no_dups([], _) --> [].
no_dups([H|T], Seen) -->
{ memberchk(H, Seen) },
!,
no_dups(T, Seen).
no_dups([H|T], Seen) -->
[H],
no_dups(T, [H|Seen]).
Well, these are the "while loops" of Prolog on the one hand, and the inductive definitions of mathematical logic on the other hand (See also: Logic Programming, Functional Programming, and Inductive Definitions, Lawrence C. Paulson, Andrew W. Smith, 2001), so it's not surprising to find them multiple times in a program - syntactically similar, with slight deviations.
In this case, you just have a binary decision - whether something is the case or not - and you "branch" (or rather, decide to not fail the body and press on with the selected clause) on that. The "guard" (the test which supplements the head unification), in this case member(X,Ys) or \+ member(X,Ys) is a binary decision (it also is exhaustive, i.e. covers the whole space of possible X)
intersect([X|Xs],Ys,[X|Acc]) :- % if the head could unify with the goal
member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
intersect([X|Xs],Ys,Acc) :- % if the head could unify with the goal
\+ member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
Other applications may need the equivalent of a multiple-decision switch statement here, and so N>2 clauses may have to be written instead of 2.
foo(X) :-
member(X,Set1),
(...action...).
foo(X) :-
member(X,Set2),
(...action...).
foo(X) :-
member(X,Set3),
(...action...).
% inefficient pseudocode for the case where Set1, Set2, Set3
% do not cover the whole range of X. Such a predicate may or
% may not be necessary; the default behaviour would be "failure"
% of foo/1 if this clause does not exist:
foo(X) :-
\+ (member(X,Set1);member(X,Set2);member(X,Set3)),
(...action...).
Note:
Use memberchk/2 (which fails or succeeds-once) instead of member/2 (which fails or succeeds-and-then-tries-to-succeed-again-for-the-rest-of-the-set) to make the program deterministic in its decision whether member(X,L).
Similarly, "cut" after the clause guard to tell Prolog that if a guard of one clause succeeds, there is no point in trying the other clauses because they will all turn out false: member(X,Ys),!,...
Finally, use term comparison == and \== instead of unification = or unification failure \= for delete/3.

delete all occurences of a term in a list

I know this sounds "duplicate" but please help me out
I have defined three terms as follows:
type([a, b, c, d]:location).
type([coffee, tea, lemonade, water, biscuits]: object).
type([order(object, location)]: order).
I have a piece of code that then generates a list of random orders.
I now need a predicate that deletes all the terms that unify with order(X, a), that is, deletes all the orders that have a as location from that list.
For instance, this is an example of list (printed this way to make it readable):
order(tea,a)
order(tea,b)
order(coffee,b)
order(water,c)
order(lemonade,d)
order(biscuits,a)
order(water,c)
order(tea,c)
order(coffee,d)
order(water,d)
applying such needed predicate my_delete(List, [order(_, a), order(_, b)], Result) would give:
order(water,c)
order(lemonade,d)
order(water,c)
order(tea,c)
order(coffee,d)
order(water,d)
So far I've tried to remove a sublist from the main list, but what it does is just delete a single element for a and a single element for b, not all of them. This is the code for such predicate (thanks also to this reference):
remove_list([], _, []).
remove_list([X|Tail], L2, Result):-
member(X, L2),
!,
remove_list(Tail, L2, Result).
remove_list([X|Tail], L2, [X|Result]):-
remove_list(Tail, L2, Result).
and a query that I tried, but didn't work as expected, was:
remove_list(Input_list, [ordine(_, a), ordine(_, b)], Result).
Notice that I need duplicates, so using sets won't work.
You can use negation \+ to avoid further unification over recursion of your filter list:
remove_list([], _, []).
remove_list([X|Tail], ToDelete, Result):-
(\+( memberchk(X, ToDelete) ) ->
Result=[X|NResult] ;
Result=NResult
),
remove_list(Tail, ToDelete, NResult).
Using exclude/3, which takes a predicate, input list and output list:
rev_memberchk(List, Member) :-
memberchk(Member, List).
my_delete(Input_List, Orders, Result) :-
exclude(rev_memberchk(Orders), Input_List, Result).
Using memberchk/1 rather than member/2 for efficiency; you don't need the bound output, just to know if it can unify. If you also have lambda expressions, this can be turned into a one-liner by removing the need to write a predicate with re-ordered arguments:
my_delete(Input_List, Orders, Result) :-
exclude({Orders}/[X]>>memberchk(X, Orders), Input_List, Result).

why does bubblesort([8,7,6,5,4,3,2,1],L). return unsorted list?

bubblesort(inputList, SortList) :-
swap(inputList, List), !,
printlist(List),
bubblesort(List, SortList).
bubblesort(SortList, SortList).
swap([X,Y |List], [Y,X|List]) :- X>Y.
swap([Z|List], [Z|List1]) :- swap(List,List1).
printlist([]) :- nl.
printlist([Head|List]) :-
write(Head), write(" "),
printlist(List).
You need to call it like this:
bubblesort(SortList, NewSortList)
Since you are putting the same list as input and output, the swap([X,Y |List], [Y,X|List]) rule will never match anything.
EDIT: Also, the swap predicate might be missing an end clause swap([], []).
EDIT 2: On second look, it isn't. The swap predicate will purposefully fail if it doesn't swap anything, so that bubblesort can continue to the bubblesort(SortList, SortList). clausule without getting stuck in an infinite recursion. I'm not sure if that is elegant or ugly code design.
I got it, It will be InputList instead of inputList.

Help with simple prolog exercise

I haven't been able to solve this prolog exercise. I was hoping someone here could give me some hints or post a solution. Thanks in advance.
Database:
lig(super, porto).
lig(super, benfica).
lig(super, sporting).
lig(honra, feirense).
lig(honra, guimaraes).
jog(sporting, ricardo, gr).
jog(guimaraes, cleber, de).
jog(feirense, edgar, me).
jog(porto, quaresma, av).
jog(porto, helton, gr).
jog(benfica, simao, av).
jog(sporting, moutinho, me).
The sample output:
?- calcula(Lista).
Lista = [super-[porto-[quaresma,helton], benfica-[simao], sporting-
[moutinho,ricardo]], honra-[ feirense-[edgar], guimarĂ£es-[cleber]]].
My procedure:
calcula(Lista) :-
findall(Lig-[Eq-[X]],
(lig(Lig, Eq), findall(Jog, jog(Eq, Jog, _), X)),
Lista).
My output (which is wrong!).
Lista = [super-[porto-[[quaresma, helton]]], super-[benfica-[[simao]]], super-[sporting-[[ricardo, moutinho]]], honra-[feirense-[[edgar]]]
I see in the zfm's solution, the predicate lig(Lig, _) becomes true 5 times so there is some duplication in the final list. You can use the predicate setof/3 and existential quantified variable Eq0^ to remove duplication:
calcula(T) :- setof(Lig-X, Eq0^(lig(Lig, Eq0),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T).
Since I'm so interested to the question, I try it a lot.
Well, this is, I believe, not the best answer. However I get the result.
calcula(Ans):-findall(Lig-X, (lig(Lig, _),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T),
removeEq(T,Ans).
removeEq([A-B,A-_|Tail], [A-B|TailChanged]) :- !, removeEq([A-B|Tail],
[A-B|TailChanged]).
removeEq([A-B,C-D|Tail], [A-B,C-D|TailChanged]) :- removeEq([A-B|Tail],
[A-B|TailTemp]), removeEq([C-D|TailTemp], [C-D|TailChanged]).
removeEq([X], [X]).
The removeEq is needed because there are duplicated answer (I don't know how not to duplicate it)
This is not shorter than zfm's answer, but it is "simpler" in the way that it only uses basic prolog constructs to construct the list directly. (No removal of duplicates afterward.) There is some code duplication which probably could be gotten rid of to get a shorter answer.
g(Second, [Third|Rest], Done) :- jog(Second, Third,_),
not(member(Third, Done)),!,
g(Second, Rest, [Third|Done]).
g(_,[],_).
f(First, [Second-New|Rest], Done) :- lig(First, Second),
not(member(Second, Done)),!,
g(Second, New, []),
f(First, Rest, [Second|Done]).
f(_,[],_).
h([First-X|Lista], Done):-
lig(First,_),
not(member(First, Done)),!,
f(First, X, []),
h(Lista,[First|Done]).
h([], _).
calcula(X) :- h(X, []).

Prolog difference routine

I need some help with a routine that I am trying to create. I need to make a routine that will look something like this:
difference([(a,b),(a,c),(b,c),(d,e)],[(a,_)],X).
X = [(b,c),(d,e)].
I really need help on this one..
I have written a method so far that can remove the first occurrence that it finds.. however I need it to remove all occurrences. Here is what I have so far...
memberOf(A, [A|_]).
memberOf(A, [_|B]) :-
memberOf(A, B).
mapdiff([], _, []) :- !.
mapdiff([A|C], B, D) :-
memberOf(A, B), !,
mapdiff(C, B, D).
mapdiff([A|B], C, [A|D]) :-
mapdiff(B, C, D).
I have taken this code from listing(subtract).
I don't fully understand what it does, however I know it's almost what I want. I didn't use subtract because my final code has to be compatible with WIN-Prolog... I am testing it on SWI Prolog.
Tricky one! humble coffee has the right idea. Here's a fancy solution using double negation:
difference([], _, []).
difference([E|Es], DL, Res) :-
\+ \+ member(E, DL), !,
difference(Es, DL, Res).
difference([E|Es], DL, [E|Res]) :-
difference(Es, DL, Res).
Works on SWI-PROLOG. Explanation:
Clause 1: Base case. Nothing to diff against!
Clause 2: If E is in the difference list DL, the member/2 subgoal evaluates to true, but we don't want to accept the bindings that member/2 makes between variables present in terms in either list, as we'd like, for example, the variable in the term (a,_) to be reusable across other terms, and not bound to the first solution. So, the 1st \+ removes the variable bindings created by a successful evaluation of member/2, and the second \+ reverses the evaluation state to true, as required. The cut occurs after the check, excluding the 3rd clause, and throwing away the unifiable element.
Clause 3: Keep any element not unifiable across both lists.
I am not sure, but something like this could work. You can use findall to find all elements which can't be unified with the pattern:
?- findall(X, (member(X, [(a,b),(b,c),(a,c)]), X \= (a,_)), Res).
gets the reply
Res = [ (b, c) ]
So
removeAll(Pattern, List, Result) :-
findall(ZZ109, (member(ZZ109, List), ZZ109 \= Pattern), Result).
should work, assuming ZZ109 isn't a variable in Pattern (I don't know a way to get a fresh variable for this, unfortunately. There may be a non-portable one in WIN-Prolog). And then difference can be defined recursively:
difference(List, [], List).
difference(List, [Pattern|Patterns], Result) :-
removeAll(Pattern, List, Result1),
difference(Result1, Patterns, Result).
Your code can be easily modified to work by making it so that the memberOF predicate just checks to see that there is an element in the list that can be unified without actually unifying it. In SWI Prolog this can be done this way:
memberOf(A, [B|_]) :- unifiable(A,B,_).
But I'm not familiar with WIN-PRolog so don't know whether it has a predicate or operator which only tests whether arguments can be unified.

Resources