Merge alternate elements from two lists in Prolog - list

I need to write a Prolog predicate mergealt(X,Y,Z) that succeeds if the list Z is a merger of alternate elements from the lists X and Y.
The input and output will like below:
?- mergealt([1,2,3,4],[6,7,8],Z).
Z = [1, 7, 3] .
?- mergealt([1,2,3,4],[6,7,8,9],Z).
Z = [1, 7, 3, 9] .
?- mergealt([1,2,3,4],[6,7,8,9,10],Z).
Z = [1, 7, 3, 9] .
I don't really understand recursion. How can I get started on this problem?

Prolog can be considered the 'flagman' of declarative languages.
So try to describe your problem, top down:
mergealt(X, Y, Z) :-
'take first element from X and put it in Z',
'discard first element from Y',
'mergealt rest-of-X and rest-of-Y, but exchange them'.
First step can't be accomplished if there are no elements in X.
This fact highlights the recursion termination case. Originally, Prolog didn't used if then else, instead alternatives are stated as different rules:
mergealt([], _Y, []).
Here you can see that pattern matching on first argument it's the key to distinguish alternatives, and contextually, Z get bound to an empty list. Y is unused, so it's marked as anonymus place holder, just to avoid a warning.
Then this simpler case suggests that we should use pattern matching to accomplish those verbose descriptions. See if you can complete the procedure with these guidelines:
mergealt([X|Xs], Y, [X|Zs]) :-
% take first element from X and put it in Z : done in the head
% discard first element from Y : see below
% mergealt rest-of-X and rest-of-Y, but exchange them'. : make your recursive call
discard_first_element([_|Rest], Rest).
% why is this necessary? do you see where it fails if we don't specify this case?
discard_first_element([], []).

Notice that the result always starts with the first element of the first list.
This means that, if the first list is empty, you know the answer right away.
Also notice that, if it isn't empty, we already know the first item of the result, so we need to use mergealt to compute the rest. But "the rest" will have the second item of the second list as the first item of the result, and as we said above, that means that a call to mergealt to compute it would have to have that be the first item of the first list (yeah, this is the tricky part).

Related

run length decoding of a list in prolog?

I'm trying to decode a given list for example mydecode([(a,1), (b,2), (c,3), (d,2)],X) should give X = ['a','b','b','c','c','c','d','d']. What is the error in this code?
mydecode([],[]).
mydecode([X|Ys],[X|Zs]) :- \+ is_list(X), mydecode(Ys,Zs).
mydecode([[1,X]|Ys],[X|Zs]) :- mydecode(Ys,Zs).
mydecode([[N,X]|Ys],[X|Zs]) :- N > 1, N1 is N - 1, mydecode([[N1,X]|Ys],Zs).
you are asked to handle a list of 'tuples' of 2 elements, not a list of lists of 2 elements
then, the test in the second clause will always fail
the tuples elements are key and value, but you're 'accessing' them in inverse order.
So, remove the second clause - it's irrelevant, since pattern matching will discard ill formed lists.
Change the [1,X] to (X,1) and similarly other references to tuples, and test your code with the query assigned.

Reverse every second list of lists in Prolog

I have a list containing lists and I want to reverse every second list in it. I tried something but if I have odd number of elements in the list the last list element is lost... So the best solution would be to put the odd lists first and the even lists second till every second list is reversed.
I can't use any libraries. I need to do it recursively or split them and append them again. The best thing I made so far was to reverse only the first even list and append the first odd and even list in a new list.
I tried to do this:
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
And this:
reverselist(List1, List2).
reverselist([H|Ts], [Odd|R]):-
not(0 is H mod 2),
append(H, [], Odd),
reverselist(Ts, R).
reverselist([H|Ts], [Even|R]):-
0 is H mod 2,
reverse(H, Even),
reverselist(Ts, R).
Sample query:
?- reverselist([[a,b,c],[d,a,b],[c,d,o],[b,c,d],[e,e,d]], List).
I want the result to be:
List = [ [a,b,c],[b,a,d],[c,d,o],[d,c,b],[e,e,d] ].
You can also write mutual recursion:
reverselist([],[]).
reverselist([H|T],[H|T1]):-reverselist2(T,T1).
reverselist2([],[]).
reverselist2([H|T],[H1|T1]):-reverse(H,H1), reverselist(T,T1).
You were pretty close with your first variant.
Instead of your
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
just tweak it as
reverselist([], []). % additional clause
reverselist([List], [List]).
reverselist([X,Y|Rest], [X,EvenList|Rest2]):-
reverse( Y, EvenList),
reverselist( Rest, Rest2).
All three clauses are mutually exclusive and together they are exhaustive, i.e. they cover every possibility.
I believe this definition to be the most immediate and close representation of your problem. In Prolog, to formulate the problem means to have the solution for it.
We need to create another predicate with one more argument to keep track of odd or even position:
reverselist(InList,OutList):- reverselist(InList,OutList, 0).
reverselist([],[],_). %base case
%case of even position
reverselist([H|T],[H|T1], 0):- reverselist(T,T1,1).
%case of odd position
reverselist([H|T],[H1|T1], 1):- reverse(H1,H), reverselist(T,T1,0).

Define the predicate maxlist( List, Max) so that Max is the greatest number in the list of numbers List

Exercise 3.17 “ Prolog Programming for Artificial Intelligence” by
Ivan Btrako
I understand the max predicate, but I'm having trouble tracing the maxList one. I'm trying to write the logic in pseudocode to help me out
Take first and second elements and compare them and get the
maximum
Take that maximum and compare it with third element in
list and if it's bigger overwrite the maximum and repeat again till
list is empty.
I don't understand the solution given however, and I tried tracing it and failed. I'm having trouble mapping the MaxRest to the Max & with the base case. Also, I don't understand why prolog doesn't give an error when unifying [X,Y|Rest] with [Y|T]. Example [1,3,[7,2]] with [3|[7,2]].
max(X,Y,X):-
X>=Y.
max(X,Y,Y):-
X<Y.
maxlist( [X], X). %what does this line do?
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
Any help tracing would be greatly appreciated.
Since you understand max/3 this won't explain it.
maxlist( [X], X). %what does this line do?
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
This is a classic recursive list pattern that does the recursion before processing the item. The normal recursive list pattern with a tail-call is
process_list([H|T],R) :-
process_item(H,R),
process_list(T,R).
process_list([],R).
but here it is
process_list([H|T],R) :-
process_list(T,R),
process_item(H,R).
process_list([],R).
where the item is processed after recursing through the list.
Also this processes two items at a time, i.e.
[H1,H2|T]
because the compare needs two items.
This
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
is just taking the values off of the list and pushing them onto the stack so that when it backtracks it will have one value for the comparison, i.e. MaxRest which is the max of all the values that were in Rest and the current value which is X. You might think it should be Y, but when there is just one item in the list, the list is actually [Y|[]] which is really [Y] with matches with the pattern in this clause maxlist( [X], X)..
So what does maxlist( [X], X). do? A common base case for a list is just predicate([],R). for returning a list, but in this case the last value alone needs to be returned as a value, so this takes X out of the list in the first parameter and returns it as a value in the second parameter so that it becomes MaxRest which is the max value when there is only one item in the list. When max(X, MaxRest,Max) is executed it has a value for MaxRest return from backtracking, and X on the stack when deconstructing the list. The result is Max which is returned as the third parameter in maxlist( [X,Y|Rest], Max) which becomes the value for MaxRest upon backtracking again.
Ask questions if that doesn't make sense.
I don't understand why Prolog doesn't give an error when unifying
[X,Y|Rest] with [Y|Rest].
Example [1,3,[7,2]] with [3|[7,2]]
Actually
?- [1,3,[7,2]] = [3|[7,2]].
false.
so while your example does give an error, it is not what is being done with
[X,Y|Rest] and [Y|Rest]
Start with the list [1,2,3,4] and unify it with[X,Y|Rest]
?- [1,2,3,4] = [X,Y|Rest].
X = 1,
Y = 2,
Rest = [3, 4].
Notice that [Y|Rest] would then be [2|[3,4]].
?- [1,2,3,4] = [X,Y|Rest],A = [Y|Rest].
X = 1,
Y = 2,
Rest = [3, 4],
A = [2, 3, 4].
Don't try an unify [X,Y|Rest] with [Y|Rest] but instead unify Rest with Rest and Y with Y, X is stored on the stack but not passed to next level of the stackframe.
If you really want to understand list then use this to see them
?- write_term([1,2,3,4],[dotlists(true)]).
.(1,.(2,.(3,.(4,[]))))
true.
If you have Version 4 of the book see Figure 3.1 on page 61.
Prolog predicates define relations in terms of logic that says that the head of the clause is true if (:-) the body is true. This helps you properly read a predicate:
max(X,Y,X):-
X>=Y.
This says that:
X is the maximum of X and Y if X >= Y is true.
You can similarly read the clause for max(X,Y,Y).
Now look at:
maxlist( [X], X).
Here, we're defining maxlist to mean the maximum value of a list. This particular clause says that:
X is the maximum value of the list [X].
There are no if conditions (:-) in this case since no other conditions are necessary to establish this rule.
Then there is the recursive clause:
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
This says that:
Max is the maximum value of list [X,Y|Rest] if MaxRest is the maximum of list [Y|Rest] and Max is the maximum value of X and MaxRest.
This recursive clause and the prior base case clause completely define maxlist. If you read through that carefully, it should seem completely logical.
I don't understand why prolog doesn't give an error when unifying [X,Y|Rest] with [Y|T]
I don't understand this comment. Nowhere in your code does Prolog attempt to unify these two terms. Your example terms of [1,3,[7,2]] and [3|[7,2]] would not unify because the first is a list of three elements: 1, 3, and [7,2], whereas the other is a list of 3 elements: 3, 7, and 2. For two lists to be unifiable, it not only needs to be the same length, but each corresponding term in the list must be unifiable.
What would then make [X,Y|Rest] and [Y|T] unifiable? You can write [X,Y|Rest] as [X|[Y|Rest]], which makes it easy to see that these are unifiable if the following are true:
X = Y,
[Y|Rest] = T
In other words, the lists have to have (a) at least two elements, and (b) the first two elements are the same.

Need to remove last but one element in prolog

I have been trying to do different things in prolog and want to remove the last but one element and i don't know how.
This is my code:
without(X,[X,_],[]).
without(X,[K|Xs],[K|AlmoustLast]) :-
without(X,Xs,AlmoustLast).
And this is what i receive when compiling.
?- without(X,[1,2,3,4,5],A).
X = 4,
A = [1, 2, 3] .
When the answear I am trying to achieve is A = [1,2,3,5].
You were almost right with
without(X,[X,_],[]).
without(X,[K|Xs],[K|AlmoustLast]) :-
without(X,Xs,AlmoustLast).
In fact, the following
without(X,[X,Y],[Y]).
without(X,[K|Xs],[K|AlmostLast]) :-
without(X,Xs,AlmostLast).
gives you
?- without(X,[1,2,3,4,5],A).
A = [1,2,3,5]
X = 4
Rafalon gave the corrected result, to which I'll provide an explanation.
You're base case rule logic is flawed:
without(X,[X,_],[]).
Here you're saying that if you remove the last but one from [X,_], then you get element X and list [], but that doesn't sound logical, does it? What happened to _? You're using an anonymous variable here implying you don't care about it, but you really do care! As Rafalon indicates, this rule should be:
without(X, [X,Y], [Y]).
So that the last but one of the list [X, Y] gives you the element X and the list [Y].

Return from Prolog predicate

I have a predicate, which is true, if passed such list of pairs, for instance:
translatable([(dog,perro)], [(perro,hund)], [(dog,hund)])
Means - if "dog" translates to "perro", and "perro" translates to "hund", then it is true that "dog" translates to "hund".
Here follows full code. Returns/suggests first member of pair - given ((a, b), a) returns true, given ((a, b), X) returns X = a:
first((First, _), First).
Similar to "first", but for second pair member:
second((_, Second), Second).
This returns true if translatable word exists in list of tuples, and saves translation to Translation: (dog, Translation, [(bed,cama),(dog,perro)]
translation_exists(Word, Translation, [H|T]) :-
first(H, Word), second(H, Translation), !;
translation_exists(Word, Translation, T).
And resulting:
translatable(EnglishSpanish, SpanishGerman, EnglishGerman) :-
forall(member(Pair, EnglishGerman), (
first(Pair, Word),
second(Pair, ResultTranslation),
translation_exists(Word, Translation, EnglishSpanish),
translation_exists(Translation, ResultTranslation, SpanishGerman)
)).
This code returns true/false correctly.
But why, given
translatable([(dog,perro)], [(perro,hund)], X).
It does not returns X = [(dog,hund)]?
EDIT
To be more specific, actual goal is:
to find out if LAST dictionary has translatable pairs (and them only).
Daniel, thanks a lot, I have adopted your suggested member function - great simplification, thank you! This is all the code I have now:
lastIsTranslatable(_, _, []).
lastIsTranslatable(EngSpan, SpanGerm, [(Eng, Germ) | T]) :-
member((Eng, Span), EngSpan),
member((Span, Germ), SpanGerm),
% this is to protect endless [(dog,hund), (dog, hund), ...]
not(member((Eng, Germ), T)),
lastIsTranslatable(EngSpan, SpanGerm, T),
!.
And still, this works great finding True & False:
lastIsTranslatable([(a,b)], [(b,c)], [(a,c)]).
lastIsTranslatable([(a,b)], [(b,c)], [(a,no)]).
But for
lastIsTranslatable([(a,b)], [(b,c)], X).
result is X= [], then, after hitting ";" - false. Why?
Well, running with trace option, I see execution is failing on
not(member((Eng, Germ), T))
But otherwise resulting X will be endlessly filled with (a,c), (a,c)... Maybe there is better way to protect from duplicates?
The reason, basically, is that because EnglishGerman is uninstantiated, member/2 is free to come up with possible lists for it:
?- member((perro,X), List).
member((perro,X), List).
List = [ (perro, X)|_G18493911] ;
List = [_G18493910, (perro, X)|_G18493914] ;
List = [_G18493910, _G18493913, (perro, X)|_G18493917] ;
List = [_G18493910, _G18493913, _G18493916, (perro, X)|_G18493920]
...
This is the most direct issue, but even if you change the flow of data I think you'll still have problems:
translatable1(EnglishSpanish, SpanishGerman, EnglishGerman) :-
member((English,Spanish), EnglishSpanish),
member((Spanish,German), SpanishGerman),
member((English,German), EnglishGerman).
Note that I have foregone your first/2 and second/2 predicates in favor of pattern matching; I think this reads more clearly.
Aside: If you know your list is concrete and you don't want to generate multiple solutions, you can use memberchk/2 to verify that an element exists instead of member/2; it's cheaper and deterministic.
This works better (you get solutions, anyway) but still you get a lot more solutions than you need:
?- translatable1([(dog,perro)], [(perro,hund)], X).
X = [ (dog, hund)|_G18493925] ;
X = [_G18493924, (dog, hund)|_G18493928] ;
X = [_G18493924, _G18493927, (dog, hund)|_G18493931] a
Something which we know that our code does not know is that the cardinality of the result set should be less than or equal to the lowest cardinality of our inputs; if I have fifteen English-Spanish words and twelve Spanish-German words, I can't have more than twelve words in my English-German result. The reason our code doesn't know that is because it is trying to behave like math: our code is basically saying "for every element of English-Spanish, if there exists a matching element of Spanish-German, that is also an element of English-German." This does not tell us how to construct English-German! It only tells us a fact about English-German that we can verify with English-Spanish and Spanish-German! So it's cool, but it isn't quite enough to compute English-German.
Aside: it's conventional in Prolog to use a-b instead of (a,b); it's too easy to lull yourself into believing that Prolog has tuples when it doesn't and the operator precedence can get confusing.
So, how do we tell Prolog how to compute English-German? There are probably lots of ways but I would prefer to use select/3 because our set cardinality constraints (as well as a general sense that it will converge/halt) will emerge naturally from a computation that "uses up" the input sets as it goes.
translatable2([], _, []).
translatable2(_, [], []).
translatable2([Eng-Span|EngSpanRem], SpanGerm, EngGerm) :-
(select(Span-Germ, SpanGerm, SpanGermRem) ->
translatable2(EngSpanRem, SpanGermRem, EngGermRem),
EngGerm = [Eng-Germ|EngGermRem]
;
translatable2(EngSpanRem, SpanGerm, EngGerm)
).
The base cases should be obvious; if we are out of English-Spanish or Spanish-German, there's nothing left to compute. Then the inductive case peels the first item off the English-Spanish list and searches for a Spanish-German translation that matches. If it finds one, it uses it to build the result; otherwise, it just recurs on the remaining English-Spanish list. This way, on each iteration we at least discard an English-Spanish translation from that list, and we discard Spanish-German translations as they are used. So it seems intuitively likely that this will work and terminate without producing a bunch of extra choice points.
It seems to do the trick:
?- translatable2([dog-perro], [perro-hund], X).
X = [dog-hund] ;
X = [dog-hund].
The extra result there is because we hit both terminal cases because both lists became []; this isn't attractive but it isn't anything to worry about really either.
Now one thing that sucks about this solution is that it treats the first two parameters as in-parameters and the last one as an out-parameter and there isn't really anything you can do about this. I don't know if this is an issue for you; translatable/1 should not have this limitation, but because member((Spanish,German), SpanishGerman) happens before member((English,German), EnglishGerman) it winds up generating an infinitely large list, searching in effect for the missing Spanish-German translation.
Still, it feels like it should be possible to come up with a general purpose predicate that works as long as you supply any two of these inputs. I can do that if I know that all three lists are complete and in the same order:
translatable3([], [], []).
translatable3([X-Y|XYs], [Y-Z|YZs], [X-Z|XZs]) :-
translatable3(XYs, YZs, XZs).
And you can see it work like so:
?- translatable3([dog-perro], [perro-hund], X).
X = [dog-hund].
?- translatable3([dog-perro], X, [dog-hund]).
X = [perro-hund].
?- translatable3(X, [perro-hund], [dog-hund]).
X = [dog-perro].
But I don't know enough about your constraints to know if that could be a legitimate answer. My suspicion is no, because languages don't work that way, but who knows?
Anyway, that's three different approaches; I hope one of them is helpful to you!