I am defining a function alternate_func(Ps, P) where Ps is a list of lists and P is a list of all elements in Ps that behaves in the following way: .
?- alternate_func([[p,q],[r,s]],P).
P=[p,r,q,s]. (case 1)
?- alternate_func([P,Q,R],[p,q,r,s,t,u]).
P=[p,s], Q=[q,t], R=[r,u]. (case 2)
?- alternate_func([Q],[1,2,3]).
Q=[1,2,3]. (case 3)
?- alternate_func([[4,5,6],[3,1],[4,1,2]],X).
false. (because Length of sublists must be same) (case 4)
This is what I have tried so far,
alternate_func([[], L], L).
alternate_func([[H|T], []], [H|T]).
alternate_func([[X|L1], [Y|L2]], [X,Y|L3]) :-
alternate_func([L1, L2], L3).
I am getting correct result for the case 1 but fails for the 2,3 and 4. What is the problem here?
In Prolog list elements are enclosed by brackets and separated by commas. Another way to represent a list is to use the head/tail notation [H|T]. Here the head of the list, H, is separated from the tail of the list, T, by a vertical bar. The tail of a list is the original list with its first element removed.
1. print all elements of a list ?-print_list([a,b,c]). a b c print_list([]):-nl. %nl = newline print_list([HT]):-write(H),write(' '),print_list(T).
You can move unification into the head of the clause and simply write: second([_, Second| _], Second). The notation for lists is to write the initial elements separated by commas and then a vertical bar to separate the list tail, i.e. the list containing the rest of the elements.
To sum the elements in a list inductively, we add the first element to the sum of the remaining ones. In Prolog we say this: sum([H|T], S) :- sum(T,X), S is H + X.
This solution processes the list of lists splitting the head / tail off each list. Afterwards:
Code:
lists_interleaved( Ess, Es):-
lists_interleaved( Ess, X-X, Es).
lists_interleaved( [], Head-[], []):-
maplist(=([]), Head).
lists_interleaved( [], [First|Head]-[], Es):-
lists_interleaved( [First|Head], X-X, Es).
lists_interleaved( [[E|ETail]|Ess], Head-[ETail|Rest], [E|Es]):-
lists_interleaved( Ess, Head-Rest, Es).
First, stick to good naming of relations. There is no func
tion here. You have a relation between a list of lists and a list. So a name lists_interleaved(Ess, Es)
is preferable.
:- set_prolog_flag(double_quotes, chars). % to permit that "abc" = [a,b,c]
lists_interleaved(Ess, Es) :-
transpose(Ess, EssT),
phrase(seqq(EssT), Es). % alternatively append(EssT,Es)
See the definition of seqq//1
.
Still this is not the nicest definition. After all, ?- lists_interleaves(Ess, "abcd").
does not terminate. Let's use a failure-slice to see why:
lists_interleaved(Ess, Es) :- transpose(Ess, EssT), false,phrase(seqq(EssT), Es). ?- lists_interleaved(Ess, "abcd"), false. loops.
A simple way to fix this is to establish a relation between Ess
and Es
.
After all, the first list in Ess
can be at most as long as Es
, and also Ess
cannot be longer.
By adding these restrictions as extra goals, we get:
lists_interleaved(Ess, Es) :- Ess = [Fs|_], Fs = [_|_], list_longer(Ess, Es), list_longer(Fs, Es), transpose(Ess, EssT), phrase(seqq(EssT), Es). list_longer([], _). list_longer([_|Es], [_|Fs]) :- list_longer(Es, Fs).
This now constrains us to an Es
with at least one element.
?- lists_interleaved(Ess, "abcdef").
Ess = ["abcdef"]
; Ess = ["ace","bdf"]
; Ess = ["ad","be","cf"]
; Ess = ["a","b","c","d","e","f"]
; false.
See this answer how to print solutions using compact double-quotes notation.
And still, this isn't perfect as these list_longer/2
goals are now essentially guessing. But I will leave it as is since this is what you asked for.
(I will put a bounty for a better definition/or justification why this is not possible)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With