I need to write a predicate longestList/2 such that longestList(L1,L2) is satisfied if L2 is the longest
nested list from the list of lists L1.
?- longestList([[1],[1,2],[1,2,3],[1,2,3,4]],LI).
LI = [[1, 2, 3, 4]] ;
No
?- longestList([[a,b,c],[d,e],[f,g,h]],LI).
LI = [[f, g, h],[a,b,c]];
No
Could someone please help me with intuition to go about solving it?
Here's an outline for a basic, recursive approach. Not quite as crisp as the answer #CapelliC gave, but on the same order of simplicity.
The idea is to traverse the list and keep track of the longest list you've seen so far, and what it's length is. Then you step through the list recursively and update these arguments for the recursion if the conditions indicate so. It's a slight elaboration on the technique used to do a recursive "max list element" predicate. To do this, you set up a call to include more arguments (the current longest list, and its length).
longestList([], []).
longestList([L|Ls], LongestList) :-
length(L, Length),
% Start with the first element (L) being my best choice so far
longestList(Ls, L, Length, LongestList).
Here is the expanded predicate with the new arguments.
longestList([L|Ls], LongestListSoFar, GreatestLengthSoFar, LongestList) :-
% Here, you need to examine L and determine if it should supersede
% the longest list so far and its length. You need to keep in mind that
% if the length of L is the same as the max length so far, then I
% may choose to keep the LongestListSoFar, or choose L. Both are
% valid solutions for this call. This is a good place to use the `;`
% operator, and to be cautious about parenthesizing expressions since
% the comma has higher precedence than the semi-colon.
% Also, you'll need to make a recursive call to longestList(Ls, ??, ??, LongestList).
% The arguments to the recursion will depend upon which way the decision flow goes.
%
% After all that to-do, don't let it scare you: it's about 5 lines of code :)
%
longestList([], LongestListSoFar, ??, ??).
% Fill in the ??. What should they be at list's end ([])?
% Do I even care now what the 3rd argument is?
Hopefully that's enough to give you something to think about to make progress. Or, use #CapelliC's solution and write the member_length/3 predicate. :) Note that, as in his solution, the above solution would generate each maximum list on backtracking if there are more than one. So, you could use findall/3 if you want to get all the solutions in one list.
member/2 will allow you to peek an element (a list for your case) from a list: so, if you have a member_length/3 predicate, you could code
longestList(Lists, Longest) :-
member_length(Lists, Longest, N),
\+ ( member_length(Lists, _Another, M), M > N ).
then to find all longest, you can use findall/3...
Following code, which uses if else, seem to work partially. It has to be called with 0 length and so one cannot get length itself from here.
longest_list([H|T], LongList, LongLen):-
length(H, Len),
(Len > LongLen ->
longest_list(T, [H], Len);
longest_list(T, LongList, LongLen)).
longest_list([],Finallist,_):-writeln(Finallist).
?- longest_list([[1,2,3], [3,4], [4,5,6,7,8], [5,3,4]], Longestlist, 0).
[[4,5,6,7,8]]
true.
However, the variable itself is not coming:
?- writeln(Longestlist).
_G1955
true.
It may give some ideas.
Related
I am trying to count the elements of a list of
lists.
I implemented the code in this way:
len1([],0).
len1([_X|Xs],N) :- len1(Xs,N1), N is N1+1.
clist([[],[]],0).
clist([Xs,Ys],N):- len1(Xs,N1),len1(Ys,N2),N is N1+N2.
i re-use count element (len1 predicates) in a list, and seems work.
Anyone can say me if is nice work, very bad or can do this but it s preferable other (without len1).
I dont think is good implementation, and otherwhise seems not generic.
Ad example this work only with list, that contain two list inside. If i want make generic? i think need to use _Xs, but i try to change my code and not working.
in particular i try to change this:
clist([Xs,Ys],N):- len1(Xs,N1),len1(Ys,N2),N is N1+N2.
in
clist([_Xs],N):- len1(_Xs,N1),N is N1.
and obviously don't work.
Well you can apply the same trick for your clist/2 predicate: instead of solving the problem for lists with two elements, you can consider two cases:
an empty list [], in which case the total number is of course zero; and
a non-empty list [H|T], where H is a list, and T is the list of remaining lists. In that case we first calculate the length of H, we the calculate (through recursion) the sum of the lists in T and then sum these together.
So we can implement this as:
clist([], 0).
clist([H|T], N) :-
length(H, HN),
clist(T, TN),
N is HN + TN.
The above can be improved by using an accumulator: we can define a predicate clist/3 that has a variable that stores the total number of elements in the list this far, in case we reach the end of the list, we unify the answer with that variable, like:
clist(L, N) :-
clist(L, 0, N).
clist([], N, N).
clist([H|T], N1, N) :-
length(H, HN),
N2 is N1 + HN,
clist(T, N2, N).
Yes, you were correct in wanting to generalize your definition. Instead of
clist([[],[]],0).
(well, first, it should be
clist( [] , 0).
Continuing...) and
clist([Xs,Ys], N):- len1(Xs,N1), len1(Ys,N2), N is N1+N2.
which handles two lists in a list, change it to
clist([Xs|YSs], N):- len1(Xs,N1), len1(YSs,N2), N is N1+N2.
to handle any number of lists in a list. But now the second len1 is misapplied. It receives a list of lists, not just a list as before. Faced with having to handle a list of lists (YSs) to be able to handle a list of lists ([Xs|YSs]), we're back where we started. Are we, really?
Not quite. We already have the predicate to handle the list of lists -- it's clist that we're defining! Wait, what? Do we have it defined yet? We haven't finished writing it down, yes, but we will; and when we've finished writing it down we will have it defined. Recursion is a leap of faith:
clist([Xs|YSs], N):- len1(Xs,N1), clist(YSs,N2), N is N1+N2.
Moreover, this second list of lists YSs is shorter than [Xs|YSs]. An that is the key.
And if the lists were arbitrarily deeply nested, the recursion would be
clist([XSs|YSs], N):- clist(XSs,N1), clist(YSs,N2), N is N1+N2.
with the appropriately mended base case(s).
Recursion is a leap of faith: assume we have the solution already, use it to handle smaller sub-cases of the problem at hand, simply combine the results - there you have it! The solution we assumed to have, coming into existence because we used it as if it existed already.
recursion( Whole, Solution ) :-
problem( Whole, Shell, NestedCases),
maplist( recursion, NestedCases, SolvedParts),
problem( Solution, Shell, SolvedParts).
A Russian matryoshka doll of problems all the way down, turned into solutions all the way back up from the deepest level. But the point is, we rely on recursion to handle the inner matryoshka, however many levels it may have nested inside her. We only take apart and reassemble the one -- the top-most.
howMany([],_,0).
howMany([Head|Tail],X,Times):-
\+(Head = X),
howMany(Tail,X,Times1),
Times is Times1.
howMany([Head|Tail],X,Times):-
Head = X,
howMany(Tail,X,Times1),
Times is Times1 +1.
I have the following code for getting the length of a list in prolog, it works recursively.
Is there any other way for getting the length?
len([], 0).
len([H|T], N) :-
len(T, NT), N is NT + 1.
Any suggestions would be appreciated.
You are asking the wrong question :)
But seriously: the only sensible way of finding the length of a list is to use the built-in length/2. How it is implemented is irrelevant -- more important are its semantics:
?- length([a,b], 2).
true.
?- length([a,b], 4).
false.
?- length([a,b,c], Len).
Len = 3.
?- length(List, 3).
List = [_G937, _G940, _G943].
?- length(List, Len).
List = [],
Len = 0 ;
List = [_G949],
Len = 1 ;
List = [_G949, _G952],
Len = 2 . % and so on
Either way, it doesn't get simpler than that. Any other way of finding the length of a list, or checking for the length of a list, or creating a list of a certain length, or enumerating lists of increasing length is going to be less "simple" than using length/2.
And then: learning Prolog means learning how length/2, and the other nicely declarative built-ins can be used.
Repeating an element N times
Splitting a list into segments of some length
Exactly one pair in a list
Rotate a list
I am sure you can think of many other uses of length/2.
Here is an iterative solution that uses repeat/0 predicate:
getlength(L,N) :-
retractall(getlength_res(_)),
assert(getlength_res(0)),
retractall(getlength_list(_)),
assert(getlength_list(L)),
repeat,
(
getlength_list([]), !, getlength_res(N)
;
retract(getlength_res(V)), W is V + 1, assert(getlength_res(W)),
retract(getlength_list([_|T])), assert(getlength_list(T)), fail
).
This solution creates and retracts facts getlength_res/1 and getlength_list/1 as it walks through the list, replacing the old list with a shorter one, and the old number with a number that is greater by one at each iteration of repeat/0. In a sense, the two dynamically asserted/retracted facts behave very much like assignable variables of imperative languages.
Demo.
In general, iterative solutions in Prolog are harder to read than their recursive counterparts. This should come as no surprise, considering that anything that has an effect of an assignment statement of an imperative programming language goes against the grain with Prolog's design philosophy.
Sorry I could not resist to try out this "challenge":
Input=[a,b,b,b,b,b,b,b,b,a,b,c,d,f], between(1,inf,K),findall( _,between(1,K,_),FreeList), ( FreeList=Input,!,true).
findall/3 is doing the behind-the-scenes recursion, code is making unifications of lists FreeList and Input until they unify
I'm trying to write a simple procedure that checks if a list has any duplicates. This is what I have tried so far:
% returns true if the list has no duplicate items.
no_duplicates([X|XS]) :- member(X,XS) -> false ; no_duplicates(XS).
no_duplicates([]) :- true.
If I try no_duplicates([1,2,3,3]). It says true. Why is this? I'm probably misunderstanding Prolog here, but any help is appreciated.
To answer your questions: your solution actually fails as expected for no_duplicates([1,2,3,3]). So there is no problem.
Now take the queries:
?- A = 1, no_duplicates([A, 2]).
A = 1.
?- no_duplicates([A, 2]), A = 1.
They both mean the same, so we should expect that Prolog will produce the same answer. (To be more precise we expect the same ignoring errors and non-termination).
However, four proposed solutions differ! And the one that does not, differs for:
?- A = 2, no_duplicates([A, 2]).
false.
?- no_duplicates([A, 2]), A = 2.
Note that it is always the second query that makes troubles. To solve this problem we need a good answer for no_duplicates([A, 2]). It cannot be false, since there are some values for A to make it true. Like A = 1. Nor can it be true, since some values do not fit, like A = 2.
Another possibility would be to issue an instantiation_error in this case. Meaning: I have not enough information so I better stop than mess around with potentially incorrect information.
Ideally, we get one answer that covers all possible solutions. This answer is dif(A, 2) which means that all A that are different to 2 are solutions.
dif/2 is one of the oldest built-in predicates, already Prolog 0 did possess it. Unfortunately, later developments discarded it in Prolog I and thus Edinburgh Prolog and thus ISO Prolog.
However, current systems including SICStus, YAP, SWI all offer it. And there is a safe way to approximate dif/2 safely in ISO-Prolog
no_duplicates(Xs) :-
all_different(Xs). % the common name
all_different([]).
all_different([X|Xs]) :-
maplist(dif(X),Xs).
all_different(Xs).
See: prolog-dif
Here's yet another approach, which works because sort/2 removes duplicates:
no_duplicates(L) :-
length(L, N),
sort(L, LS),
length(LS, N).
I'd go at the problem more descriptively:
no_duplicates( [] ) . % the empty list is unique
no_duplicates( [X|Xs] ) :- % a list of length 1+ is unique
\+ member(X,Xs) , % - if its head is not found in the tail,
no_duplicates(Xs) % - and its tail is itself unique.
. %
Thinking on this, since this is a somewhat expensive operation — O(n2)? — it might be more efficient to use sort/2 and take advantage of the fact that it produces an ordered set, removing duplicates. You could say something like
no_duplicates( L ) :-
sort(L,R) , % sort the source list, removing duplicates
length(L,N) , % determine the length of the source list
length(R,N) . % check that against the result list
Or you could use msort/3 (which doesn't remove duplicates), might be a bit faster, too:
no_duplicates( L ) :-
msort(L,R), % order the list
\+ append(_,[X,X|_],R) % see if we can find two consecutive identical members
.
Duplicates in a list are same elements not at the same place in the list, so no_duplicates can be written :
no_duplicates(L) :-
\+((nth0(Id1, L, V), nth0(Id2, L, V), Id1 \= Id2)).
Jay already noted that your code is working. An alternative, slightly less verbose
no_duplicates(L) :- \+ (append(_, [X|XS], L), memberchk(X, XS)).
I'm new to Prolog and I'm stuck on a predicate that I'm trying to do. The aim of it is to recurse through a list of quads [X,Y,S,P] with a given P, when the quad has the same P it stores it in a temporary list. When it comes across a new P, it looks to see if the temporary list is greater than length 2, if it is then stores the temporary list in the output list, if less than 2 deletes the quad, and then starts the recursion again the new P.
Heres my code:
deleteUP(_,[],[],[]).
deleteUP(P,[[X,Y,S,P]|Rest],Temp,Output):-
!,
appends([X,Y,S,P],Temp,Temp),
deleteUP(P,[Rest],Temp,Output).
deleteUP(NextP,[[X,Y,S,P]|Rest],Temp,Output):-
NextP =\= P,
listlen(Temp,Z),
Z > 1, !,
appends(Temp,Output,Output),
deleteUP(NextP,[_|Rest],Temp,Output).
listlen([], 0).
listlen([_|T],N) :-
listlen(T,N1),
N is N1 + 1.
appends([],L,L).
appends([H|T],L,[H|Result]):-
appends(T,L,Result).
Thanks for any help!
Your problem description talks about storing, recursing and starting. That is a very imperative, procedural description. Try to focus first on what the relation should describe. Actually, I still have not understood what minimal length of 2 is about.
Consider to use the predefined append/3 and length/2 in place of your own definitions. But actually, both are not needed in your example.
You might want to use a dedicated structure q(X,Y,S,P) in place of the list [X,Y,S,P].
The goal appends([X,Y,S,P],Temp,Temp) shows that you assume that the logical variable Temp can be used like a variable in an imperative language. But this is not the case. By default SWI creates here a very odd structure called an "infinite tree". Forget this for the moment.
?- append([X,Y,S,P],Temp,Temp).
Temp = [X, Y, S, P|Temp].
There is a safe way in SWI to avoid such cases and to detect (some of) such errors automatically. Switch on the occurs check!
?- set_prolog_flag(occurs_check,error).
true.
?- append([X,Y,S,P],Temp,Temp).
sto. % ERROR: lists:append/3: Cannot unify _G392 with [_G395,_G398,_G401,_G404|_G392]: would create an infinite tree
The goal =\=/2 means arithmetical inequality, you might prefer dif/2 instead.
Avoid the ! - it is not needed in this case.
length(L, N), N > 1 is often better expressed as L = [_,_|_].
The major problem, however, is what the third and fourth argument should be. You really need to clarify that first.
Prolog variables can't be 'modified', as you are attempting calling appends: you need a fresh variables to place results. Note this code is untested...
deleteUP(_,[],[],[]).
deleteUP(P,[[X,Y,S,P]|Rest],Temp,Output):-
!,
appends([X,Y,S,P],Temp,Temp1),
deleteUP(P, Rest, Temp1,Output). % was deleteUP(P,[Rest],Temp,Output).
deleteUP(NextP,[[X,Y,S,P]|Rest],Temp,Output1):-
% NextP =\= P, should be useless given the test in clause above
listlen(Temp,Z),
Z > 1, !, % else ?
deleteUP(NextP,[_|Rest],Temp,Output),
appends(Temp,Output,Output1).
Currently playing around in Prolog... I'm having trouble groking the count list rule. I haven't been able to find a good explanation anywhere. Can someone give me a break down of it at each recursion?
count(0, []).
count(Count, [Head|Tail]) :-
count(TailCount, Tail),
Count is TailCount + 1.
One place says that it is recursive (which makes sense to me) and another that says it isn't.
The procedure it's recursive, but not tail recursive. Writing tail recursive procedures is an optimization that allows the system to transform recursion into iteration, avoiding useless stack usage for deterministics computations (like the one we are speaking of).
In this case (that BTW it's the same of the builtin length/2, just with arguments swapped), we can use an accumulator, and rewrite the procedure in this way:
count(C, L) :- count(0, C, L).
count(Total, Total, []).
count(SoFar, Count, [_Head|Tail]) :-
Count1 is SoFar + 1,
count(Count1, Count, Tail).
Some system older required a cut before the recursive call, to make the optimization effective:
...,
!, count(Count1, Count, Tail).
The definition of the inference rule is recursive.
This program tries to count the quantity of elements inside the list.
count(0, []). This is an axiom, a fact, something that its true because you said so. Here you are stating that every empty list has a count of zero.
count(Count, [Head|Tail]) :-
count(TailCount, Tail),
Count is TailCount + 1.
This is an inference rule, that it a rule that dictates that the left part of :- is true if the right part is true. This inference rule also uses pattern matching, wicth matchs non empty lists ([Head|Tail]).
Specifically, the count rule says that the Count variable of a non empty list is the count of the Tail part of the list, plus 1 (the plus 1 is for counting the Head element of the list).