PROLOG: Keep list in recursion - list

So, I've spent a lot of my time trying to figure this out without almost no progress. Hope you could help me.
The goal is, to take a list like this(lets call it baselist): [[[feesc,11],[podshare,11]],[[feesc,11]],[]]. And make it become this: [[feesc,22],[podshare,11]].
I have a predicate responsible to add or sum to the resulting list. Here is the code:
place_key([Key,Value], [], [Key,Value]).
place_key([Key,Value], [[Key,V]|Rest], [[Key,V1]|Rest]) :- V1 is V+Value.
place_key([Key,Value], [[K,V]|Rest], [[K,V]|List2]) :- Key \= K, place_key([Key,Value], Rest, List2)."
If I manually call this method, for simulating the recursion, it works exactly how I want.
Example:
place_key([feesc,11], [], R), place_key([feesc,11],R,J).
So J is = [[feesc,22]].
Expected result is correct.
The problem is to that with recursion.
So basically what I need to do is: iterate through the baselist, when reaching each key/par list, call place_key and keep it in the stack so the recursion keeps it until the last.
Just to point out, I don't want to append, I just need the latest result from place_key.
What I have done so far:
fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).
When I run:
[trace] 57 ?- feg([[[feesc,11]],[[feesc,11]]],R).
Call: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
Call: (7) fe([[feesc, 11]], _G21484) ? creep
Call: (8) fe([[feesc, 11]], [], _G21485) ? creep
Call: (9) place_key([feesc, 11], [], _G21485) ? creep
Exit: (9) place_key([feesc, 11], [], [[feesc, 11]]) ? creep //Until here, I think this is correct.
Call: (9) fe([], [[feesc, 11]], _G21494) ? creep
Fail: (9) fe([], [[feesc, 11]], _G21494) ? creep
Redo: (9) place_key([feesc, 11], [], _G21485) ? creep
Fail: (9) place_key([feesc, 11], [], _G21485) ? creep
Fail: (8) fe([[feesc, 11]], [], _G21485) ? creep
Fail: (7) fe([[feesc, 11]], _G21484) ? creep
Fail: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
false.
What am I doing wrong?

The problem in your case is that you don't define a base-case for fe/3. As you can see, except for your place_key predicate, you also have the following:
fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).
I'll try to make this a little more readable, so you can see what's going on:
% fe/3 cases
fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).
% fe/2 cases
fe(S,R):- fe(S,[],R).
fe([],[]).
%% this case above is never used, as the first case always matches
% recursive and base cases for feg
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).
You should rewrite this as following:
fe([],Result,Result).
This is your base case, if the list is empty, the result in-between is equal to the final result. Prolog always tries the first possible match first, so always set your base-case on top.
fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).
This is your recursive case, as you had before, which we will put below our base case.
We can drop the second fe/2 case, as the first case always matches and we rewrite to fe/3 anyway, which can handle all cases.
fe(S,R):- fe(S,[],R).
Below are your existing feg/2 cases. Here is also an error, because after your first fe/2-predicate, the RESULT-variable has a value, but it still needs to be able to unify with the call feq(T,RESULT), which will produce a different value. I'll leave this as an exercise.
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

Keep your key/pairs as a tuple, a simple term with an arity of 2. Something like K-V or K:V or even tuple(K,V) is preferable to [K,V]. There's a simple reason for this:
K-V, K:V and tuple(K,V) all map to simple structures: -(K,V), :(K,V) and tuple(K,V) respectively, while...
[K,V] is syntactic sugar for a rather more complicated structure .(K,.(V,[])).
Further, you might realize that your key/value pairs are hard to distinguish from the nested list-of-lists. Keeping the Key/Value pairs as tuples makes that distincation clear.
So, let us assume your key/value pairs are represented as K:V. It sounds to me that what you're essentially wanting to do is walk your nested list-of-lists (essentially, a tree), enumerate the key/value pairs it contains and produce the set (unique). Here's one way to do that.
First, a simple predicate to identify a non-empty list:
nonnempty_list( L ) :- nonvar(L) , L = [_|_] .
Then, a simple predicate to walk the nested list of lists and enumerate each key/value pair it finds:
visit( [ K:R | Ls ] , K:R ) . % succeed if the head of the list is a key/value pair.
visit( [ L | Ls ] , KVP ) :- % otherwise...
nonempty_list(L) , % - if the head is a non-empty list ,
visit( L , KVP ) % - visit it.
. %
visit( [_|Ls] , KVP ) :- % finally...
visit( Ls , KVP ) % - recurse down on the tail.
. %
Then you can use the magic of setof/3 to get what you want:
flattened_set( LoL , KVPs ) :-
setof( KVP , visit(LoL,KVP) , KVPs )
.

Related

Prolog Sorting a List of Structure, arithmetic error

I've been trying to sort a list of structure.
The structure is like this
% person(Name, Weight).
person(tom, 65).
person(dan, 70).
person(mike, 80).
And the list would be like this
List = [person(tom, 65), person(dan, 70), person(mike, 80)].
I want to sort the list from greatest weight to least. Like this:
SortList = [person(mike, 80), person(dan, 70), person(tom, 65)].
So far I have this:
sortListPerson([], []).
sortListPerson([person(NameP, WP)|Rest], Result):-
sortListPerson(Rest, List),
insertPerson(person(NameP, WP), List, Result).
insertPerson(person(NameP, WP), [], [person(NameP, WP)]).
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP1, WP1)|List]):-
integer(WP1),
integer(WP2),
WP1 #>= WP2,
insertPerson(person(NameP2, WP2), Rest, List).
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP2, WP2)|List]):-
integer(WP1),
integer(WP2),
WP1 #< WP2,
insertInPlace(person(NameP1, WP1), Rest, List).
I've tried with a list of two persons and it works:
?- sortListPerson([person(a, 10), person(b, 30)], SortList).
SortList = [person(b,30),person(a,10)] ? ;
But when I try with a list of 3 or more person appears an error:
?- sortListPerson([person(a, 10), person(b, 30), person(c, 40)], SortList).
{ERROR: arithmetic:>=/2 - expected an arithmetically evaluable expression, found person(a,10)}
no
?-
Can anybody help?
The way I see it your insertion-sort is okay, except for the second clause of insertPerson/3:
:- use_module(library(clpfd)).
insertPerson(person(N,W), [], [person(N,W)]).
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N1,W1),person(N2,W2)|Ps]) :-
W1 #>= W2. % If Ps is in order, we're done!
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N2,W2)|Qs]) :-
W1 #< W2,
insertPerson(person(N1,W1), Ps, Qs).
Sample query:
?- sortListPerson([person(tom,65),person(dan,70),person(mike,80)], Xs).
Xs = [person(mike,80),person(dan,70),person(tom,65)] ;
false.
The error comes from the fact that the built-in arithmetic operators like < and =< only work on instantiated terms (i.e. 1 < 2 is true but 1 < X throws the exception you mentioned). If you use constraints, the code becomes something like:
:- use_module(library(clpfd)).
smallest_in_rest_vars(person(N,A), [person(N,A)], [], [A]).
smallest_in_rest_vars(person(N,A), [person(N1,A1) | Ps], % <-- this one fails without clpfd
[person(N1,A1) | Rs], [A1|Vs] ) :-
A #=< A1,
smallest_in_rest_vars(person(N,A), Ps, Rs, Vs).
smallest_in_rest_vars(person(N1,A1), [person(N1,A1) | Ps],
[person(N,A) | Rs], [A1|Vs] ) :-
A #> A1,
smallest_in_rest_vars(person(N,A), Ps, Rs, Vs).
list_sorted([],[], []).
list_sorted(L, [Smallest|SortedRest], Vars) :-
smallest_in_rest_vars(Smallest, L, Rest, Vars0),
list_sorted(Rest, SortedRest, Vars1),
append(Vars0, Vars1, Vars).
I assume your insertInPlace predicate is similar to smallest_in_rest_vars, only without the explicit list of variables Vs which is useful for labeling (which we don't need in this case). If I would not use constraints, I'd get the following error when I query with your list:
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (9) smallest_in_rest_vars(_G400, [person(tom, 65), person(dan, 70), person(mike, 80)], [person(_G406, _G407)], _G462) ?
The reason is that the clause which is marked in the example, we don't know anything about the new person N1 yet, which leads to a comparison 80 < A1. I found using clpfd much easier to think about, but when you give us your insertInPlace, we might find a non-clp solution too.

Prolog: lists consisting of one element

I believe that the problem I have is very silly, but couldn't find an answer searching online. I want a function to always return a list of elements, even in the case the list consists of just one element. I don't know if it is always like that in prolog (i.e. that one element lists are transformed in a simple constant) but here I go into detail.
First off, I have a set of predicates (like composeBase(<,<,[<]).) based on which the function I was talking about, compose/3, makes its computations:
compose(X, Y, Z):-
compositionBase(X,Y,Z).
So, for instance, compose/3 does this:
compose(<, <, L).
L = (<) .
compose(<, =, L).
L = (<) .
compose(=, =, L).
L = (=) .
So, why in the first example does it not return [<] if the predicate says composeBase(<,<,[<]).? Is there a way to make it return the list [<] instead?
If there is not or my question doesn't make any sense, here is where the problem comes with not being able to do so (if there is, don't even bother to go on reading of course! :) Unless you feel like giving me suggestions for my naive code, which I would very much appreciate as a newbie).
I have to write a function composeList/3 which, given two lists of elements, should compute a list containing all the possible compositions of the elements in the two set.
Therefore, for example, composeList/3 should do this:
composeList([<], [<, =], L).
L = [<, =] .
composeList([<,=], [<, =], L).
L = [<, =] .
And here's the code:
composeList(_,[],[]).
composeList([],_,[]).
composeList([X| Xs], [Y| Ys], L):-
compose(X,Y,L1),
composeList(Xs, [Y| Ys], L2),
composeList([X| Xs], Ys, L3),
union(L1, L2, L4),
union(L3,L4,L).
So, as confirmed by doing trace., I believe the problem occurs when compose/3 returns a simple constant and not a list. For instance, in the example above it returns false . because, since L1 is set <, the first union fails. How can I fix this in a casual way?
By the way, here is what trace. does:
[trace] 123 ?- compositionListe([<],[<,=],L).
Call: (7) compositionListe([<], [<, =], _G8032) ? creep
Call: (8) compose(<, <, _G8122) ? creep
Call: (9) compositionBase(<, <, _G8122) ? creep
Exit: (9) compositionBase(<, <, [<]) ? creep
Exit: (8) compose(<, <, [<]) ? creep
Call: (8) compositionListe([], [<, =], _G8128) ? creep
Exit: (8) compositionListe([], [<, =], []) ? creep
Call: (8) compositionListe([<], [=], _G8131) ? creep
Call: (9) compose(<, =, _G8131) ? creep
Exit: (9) compose(<, =, <) ? creep
Call: (9) compositionListe([], [=], _G8134) ? creep
Exit: (9) compositionListe([], [=], []) ? creep
Call: (9) compositionListe([<], [], _G8137) ? creep
Exit: (9) compositionListe([<], [], []) ? creep
Call: (9) lists:union(<, [], _G8137) ? creep
Fail: (9) lists:union(<, [], _G8137) ? creep
Thank you very much in advance!

Code for Prolog program to check whether a given list is palindrome or not without using a reverse operation

This is how to get palindrome using a reverse operation.
predicates
palin(list)
findrev(list,list,list)
compare(list,list)
clauses
palin(List1):-
findrev(List1,[],List2),
compare(List1,List2).
findrev([],List1,List1).
findrev([X|Tail],List1,List2):-
findrev(Tail,[X|List1],List2).
compare([],[]):-
write("\nList is Palindrome").
compare([X|List1],[X|List2]):-
compare(List1,List2).
compare([X|List1],[Y|List2]):-
write("\nList is not Palindrome").
But I want to do it without reverse operation. Can somebody please help me.
Why not
pal([]).
pal([_]).
pal(Pal) :-
append([H|T], [H], Pal),
pal(T).
In my opinion, the most elegant way is to use a DCG, as shown here:
palindrome --> [].
palindrome --> [_].
palindrome --> [X], palindrome, [X].
Most general query:
?- phrase(palindrome, Ps).
Concrete example:
?- phrase(palindrome, [a,b,b,a]).
true .
Just match first and last elements.
first([F|L], F, L). % better inlined, but for clarity...
last(Es, L, R) :- append(R, [L], Es). % again...
palin([]).
palin([_]).
palin(L) :-
first(L, E, X), last(X, E, Y), palin(Y).
Here's one option:
palindrome( Xs ) :- palindrome( Xs , [] , Xs ) .
palindrome( [] , Z , X ) .
palindrome( [X|Xs] , T , Z ) :- palindrome( Xs , [X|T] , Z ) .
Though it's really just rolling its own implementation of reverse/2.
Another option, using append/3:
palindrome( [] ) .
palindrome( Xs ) :- append( [X|Rest] , [X] , Xs ) , palindrome(Rest) .
A third option, avoiding append/3 completely:
palindrome( [] ) . % The empty list is a palindrome
palindrome( [X] ) . % A single-element list is a palindrome.
palindrome( [X,Y|Z] ) :- % A list of more than one element is a palindrome, IF...
first( Xs , X , L1 ) , % The first element and
last( L1 , X , L2 ) , % The last element are identical, AND
palindrome(T2) % what's left over is a palindrome, too.
.
first( [X|Xs] , X , Xs ) . % getting the first item from a list is trivial.
last( [X] , X , [] ) . % getting the last item from a single element list is trivial, too.
last( [X,Y|Z] , L , [X|R] ) :- % otherwise...add the head of the list to the leftovers list,
last( [Y|Z] , L , R ) % - and recurse down on the tail
. %
A lot of these answers use last or append, which are expensive operations.
You can do half of a reverse and then check equality.
The question stipulated not to use reverse, but this only uses a reverse like process, not a full reverse.
palindrome(Xs):- palindrome(Xs,[]).
palindrome(Xs, Xs). % [1,2,2,1] will get to pal([1,2],[1,2])
palindrome([X|Xs],Xs). % captures a case like [a,b,c,b,a]
palindrome([X|Xs],Ys):- palindrome(Xs, [X|Ys]). % reverse-like process
One thing possibly missing from the above is cuts. Although no necessary here, should be used for good practice:
palindrome(Xs):- palindrome(Xs,[]).
palindrome(Xs, Xs):- !. % Don't need to redo after positive match
palindrome([X|Xs],Xs):- !.
palindrome([X|Xs],Ys):- palindrome(Xs, [X|Ys]).
Typical trace for a palindrome:
[trace] 88 ?- pal([1,2,1]).
Call: (6) pal([1, 2, 1]) ? creep
Call: (7) pal([1, 2, 1], []) ? creep
Call: (8) pal([2, 1], [1]) ? creep
Exit: (8) pal([2, 1], [1]) ? creep % Matches rule - palindrome([X|Xs],Xs).
Exit: (7) pal([1, 2, 1], []) ? creep
Exit: (6) pal([1, 2, 1]) ? creep
true .
And a non-palindrome:
[trace] 87 ?- pal([1,2,3]).
Call: (6) pal([1, 2, 3]) ? creep
Call: (7) pal([1, 2, 3], []) ? creep
Call: (8) pal([2, 3], [1]) ? creep
Call: (9) pal([3], [2, 1]) ? creep
Call: (10) pal([], [3, 2, 1]) ? creep
Fail: (10) pal([], [3, 2, 1]) ? creep % Fails as [] doesn't equal [3,2,1] and can't be pulled apart
Fail: (9) pal([3], [2, 1]) ? creep
Fail: (8) pal([2, 3], [1]) ? creep
Fail: (7) pal([1, 2, 3], []) ? creep
Fail: (6) pal([1, 2, 3]) ? creep
false.

Prolog get every second Item in a list

I want to write a Prolog predicate
evenElement(List,Term) which shoud suceed if the EvenElement is equal to Term
So far I have this code
evenElement(L,TERM) :- evenElement_rec(L,TERM).
evenElement_rec([],0).
evenElement_rec([_,HEven|T],TERM):-
evenElement_rec(T,TERM),
isEqual(HEven,TERM).
isEqual(A,B) :- A is B.
isEqual is never called, what do I have to change that this will be executed?
output is:
trace,evenElement([1,2,3,4,5,6], 4).
Call: (7) evenElement([1, 2, 3, 4, 5, 6], 4) ? creep
Call: (8) evenElement_rec([1, 2, 3, 4, 5, 6], 4) ? creep
Call: (9) evenElement_rec([3, 4, 5, 6], 4) ? creep
Call: (10) evenElement_rec([5, 6], 4) ? creep
Call: (11) evenElement_rec([], 4) ? creep
Fail: (11) evenElement_rec([], 4) ? creep
Fail: (10) evenElement_rec([5, 6], 4) ? creep
Fail: (9) evenElement_rec([3, 4, 5, 6], 4) ? creep
Fail: (8) evenElement_rec([1, 2, 3, 4, 5, 6], 4) ? creep
Fail: (7) evenElement([1, 2, 3, 4, 5, 6], 4) ? creep
false.
When you are writing a Prolog predicate, you could start like in other programming languages, digging immediately into the very problem. Or you can first think about the relation, and consider something simpler i.e. more general. You want that the first argument is a list, and the second argument is an "even" element — I assume you meant an element occurring at an even position. That is:
list_evenelement(L, E) :-
nth1(I,L,E),
I mod 2 =:= 0.
But, say you want to implement that yourself. We might start with a generalization. In this case: list_element/2 which is true for all elements:
list_element([E|_], E).
list_element([_|Es], E) :-
list_element(Es, E).
That is almost what you want. Except that it is a bit too general. That is, the set of solutions contains also answers you do not like. In particular, the first element, should not be part of the solutions. You have thus to specialize that program. We can specialize a program by adding a goal or by removing a clause (which is tantamount to adding false). Removing the fact, however, goes too far - there will no longer be any solution.
I will try it differently, and unfold the definition like so:
list_element([E|_], E).
list_element([_|Es], E) :-
list_element2(Es, E).
list_element2([E|_], E).
list_element2([_|Es], E) :-
list_element(Es, E).
That should be still our good olde definition that is too general. Now, however, we can insert false!
list_element([E|_], E) :- false.
list_element([_|Es], E) :-
list_element2(Es, E).
list_element2([E|_], E).
list_element2([_|Es], E) :-
list_element(Es, E).
This remaining part is our sought after definition, you can also put it more compactly:
list_evenelement([_,E|_], E).
list_evenelement([_,_|Es], E) :-
list_evenelement(Es, E).
Your code looks way more complicated than it has any right to be from your problem statement
I want to write a Prolog predicate evenElement(List,Term) which shoud suceed if the EvenElement is equal to Term.
Assuming that you're numbering your list elements relative to one, so for the list [a,b,c,d], the odd elements (1st and 3rd) are a and c respectively and the event elements (2nd and 4th) are b and d (rather than zero-relative, where a would be the zeroth element and c the 2nd, something like this will do. We look at the list, 2 elements at a time:
even_element( [_,T|Xs] , T ) .
even_element( [_,_|Xs] , T ) :-
even_element( Xs , T ) .

How Does Prolog print out 2 lists as one list, without any append code?

I have the following code, which is apparently the standard way to show the union between 2 lists:
union([Head|Tail],List2,Result) :-
member(Head,List2), union(Tail,List2,Result).
union([Head|Tail],List2,[Head|Result]) :-
\+ member(Head,List2), union(Tail,List2,Result).
union([],List2,List2).
and on the following input:
union([a,b,c,d,2,3], [b,c,3,99], Result).
will give me the following output:
Result = [a,d,2,b,c,3,99] ?
yes
My question is, How does prolog do this? List2 is never changed throught the recursive calls, but at the end, it prints out all elements that make the union between the 2 original lists.
Please help me understand this code.
Thank you.
let's assume that you ask union([1,2],[2],R).
according to the first rule, union([1|[2]],[2],R) would be true if
member(1,[2]) --> false
then prolog will check the second rule union([1|[2]],[2],[1|R]) will be true if
+member(1,[2]) --> true
and union([2],[2],R)
now, union([2|[]],[2],R) would be true (1st rule) if
member(2,[2]) -->true
and union([],[2],R)
union([],[2],R) would be true (3rd rule) if R=[2]
so R=[2] and therefore the first call to union returns [1|[2]] = [1,2]
a useful tool to find out "how prolog does it" is trace/0:
2 ?- trace.
true.
[trace] 2 ?- union([1,2],[2],R).
Call: (6) union([1, 2], [2], _G543) ? creep
Call: (7) lists:member(1, [2]) ? creep
Fail: (7) lists:member(1, [2]) ? creep
Redo: (6) union([1, 2], [2], _G543) ? creep
Call: (7) lists:member(1, [2]) ? creep
Fail: (7) lists:member(1, [2]) ? creep
Call: (7) union([2], [2], _G619) ? creep
Call: (8) lists:member(2, [2]) ? creep
Exit: (8) lists:member(2, [2]) ? creep
Call: (8) union([], [2], _G619) ? creep
Exit: (8) union([], [2], [2]) ? creep
Exit: (7) union([2], [2], [2]) ? creep
Exit: (6) union([1, 2], [2], [1, 2]) ? creep
R = [1, 2] .
all in all: List2 doesnt not change but the predicate does not return List2 either; it returns a list created by List2 and the unique elements of List1
The algorithm in work here is the following :
1) initialize the result to List2. This part is implemented thanks to :
union([], List2, List2).
2) go through List1 and do the following for each item :
2a) add it to Result if the item is not in List2. That part is implemented thanks to this clause :
union([Head|Tail], List2, [Head|Result]) :-
\+ member(Head, List2),
union(Tail, List2, Result).
2b) don't do anything if the item is in List2. That part is implemented thanks to this clause :
union([Head|Tail], List2, Result) :-
member(Head, List2),
union(Tail, List2, Result).
For step by step comprehension of the prolog execution, please refer to #thanosQR answer.
By the way, note that this predicate needs sets to return a good union, else, a duplicate in List1 will stay a duplicate in Result (so will a duplicate in List2).
That code it's actually rather inefficient, so we can't assume it as the 'standard way' to compute union. At first glance, there are 2 simple optimizations: avoid repeat the membership test, and use memberchk/2 instead of member/2. So we can rewrite it in the following way:
union([Head|Tail], List2, ResultT) :-
( memberchk(Head, List2)
-> ResultT = Result
; ResultT = [Head|Result] ),
union(Tail, List2, Result).
union([],List2,List2).
The difference in performance is huge. With relatively small lists:
...
numlist(1, 10000, A),
numlist(5000, 10000, B),
union(A, B, C),
...
we pass from 62,532,499 inferences to 20,002 inferences, and the test doesn't force the evaluation of all alternatives (backtrack points from member): adding this we need 25,015,004 more inferences, albeit no more solution is available. Here the code from SWI-Prolog lists library:
%% union(+Set1, +Set2, -Set3) is det.
%
% True if Set3 unifies with the union of Set1 and Set2.
% The complexity of this predicate is |Set1|*|Set2|
%
% #see ord_union/3.
union([], L, L) :- !.
union([H|T], L, R) :-
memberchk(H, L), !,
union(T, L, R).
union([H|T], L, [H|R]) :-
union(T, L, R).
It's similar to your version, please note the cut (!)