The big issue with this problem is the repeated iteration of the list and its sublists, is it not?
I would start with a predicate that iterates over your list-of-lists once, prefixing each sublist with its length, and computing the length of the sublist as it goes:
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
That's one pass over the list and its sublists.
Now that we have that, all we need is a way to extract sublists of a specified length. That's as easy as this:
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
That is another single pass of the outer list. We no longer need to iterate over the sublists themselves.
And then, we just wire up the two predicates:
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
Putting it all together, you get:
https://swish.swi-prolog.org/p/VyUrjJjD.pl
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
Overall time and space complexity is O(N).