Reputation: 5457
I wrote a predicate which should calculate the length of a list:
my_length([],0).
my_length([_|L],N) :- my_length(L,N1), N is N1 + 1.
Can anyone help in adjusting this so that it will take a list of lists and output the total number of elements in the list of lists?
Upvotes: 2
Views: 3225
Reputation: 18726
In this answer we use meta-predicate foldl/4
in combination with Prolog lambda expressions.
:- use_module(library(lambda)).
We define the predicate lists_length/2
like this:
lists_length(Xss,N) :-
foldl(\Xs^N0^N2^(length(Xs,N1),N2 is N0+N1), Xss, 0,N).
Sample query:
?- lists_length([[a,b,c],[],[d,e]], N).
N = 5.
Upvotes: 1
Reputation: 10102
I am still not the biggest fan of foldl/4
and thus I find it much more natural to state:
xss_length(Xss, N) :-
maplist(length,Xss, Ns),
list_sum(Ns, N).
Still, this does not terminate for Xss = [_,_], xss_length(Xss, 2)
. But it's a start.
Upvotes: 1
Reputation: 18663
Both the solution posted @dasblinkenlight and the original code in the question can be made tail-recursive by using accumulators, which would allow running in constant space:
my_length(List, Length) :-
my_length(List, 0, Length).
my_length([], Length, Length).
my_length([_| Tail], Length0, Length) :-
Length1 is Length0 + 1,
my_length(Tail, Length1, Length).
my_length_lol(Lists, TotalLength) :-
my_length_lol(Lists, 0, TotalLength).
my_length_lol([List| Lists], TotalLength0, TotalLength) :-
my_length(List, Length),
TotalLength1 is TotalLength0 + Length,
my_length_lol(Lists, TotalLength1, TotalLength).
Upvotes: 1
Reputation: 726479
You have most of what you need: add a rule that computes the length of a list of lists that passes the head on to my_length
:
my_length_lol([], 0).
my_length_lol([H|L],N) :- my_length(H,Add), my_length_lol(L,N1), N is N1 + Add.
As you can see, my_length_lol
("lol" stands for "List of Lists") is a near exact copy of my_length
. The only difference is that it does not ignore list head, and uses my_length
rule to compute the length of a sublist.
Upvotes: 2