[comp.lang.prolog] Definition of list_length/2

anjo@swi.psy.uva.nl (Anjo Anjewierden) (02/13/90)

Below is a definition of list_length/2 (length/2 in Edinburgh
compatibles).  I would like to know whether there is a better/shorter
solution that handles all cases and is deterministic given certain
calling patterns (see definition below).

-- Anjo.


%   list_length(?List, ?Length)
%
%   List is a list of length Length.
%
%   Note: list_length/2 is deterministic if the arguments are
%   sufficiently instantiated (i.e. if Length is given and/or
%   List is a proper list), otherwise it generates alternative
%   solutions on backtracking.

list_length(List, Length) :-
        integer(Length), !, 
        list_length_det(List, Length).	% Always deterministic
list_length(List, Length) :- 
	var(Length),
        list_length_non(List, Length).	% Possibly non-deterministic
         
/* 
list_length_non(List, N) :-		% This clause only if the Prolog
        List == [], !,			%  does not perform clause indexing.
        N = 0.
*/         
list_length_non([], 0). 
list_length_non([_|Xs], N) :-
        list_length_non(Xs, M),
        N is M+1.
         
list_length_det([], 0) :- !.
list_length_det([_|Xs], N) :-
        M is N-1,
        list_length_det(Xs, M).

lee@munnari.oz.au (Lee Naish) (02/14/90)

In article <2733@swi.swi.psy.uva.nl> anjo@swi.psy.uva.nl () writes:
>Below is a definition of list_length/2 (length/2 in Edinburgh
>compatibles).  I would like to know whether there is a better/shorter
>solution
>list_length_non([], 0). 
>list_length_non([_|Xs], N) :-
>        list_length_non(Xs, M),
>        N is M+1.

This bit is not tail recursive and can easily be improved using an
accumulator (this is something you should always look out for):

list_length_non(Xs, N) :-
	list_length_non_ac(Xs, 0, N).

list_length_non_ac([], N, N).
list_length_non_ac([_|Xs], N0, N) :-
	N1 is N0 + 1,
	list_length_non_ac(Xs, N1, N).

	lee

stolcke@icsi.Berkeley.EDU (Andreas Stolcke) (02/15/90)

In article <3179@munnari.oz.au>, lee@munnari.oz.au (Lee Naish) writes:
> 
> list_length_non(Xs, N) :-
> 	list_length_non_ac(Xs, 0, N).
> 
> list_length_non_ac([], N, N).
> list_length_non_ac([_|Xs], N0, N) :-
> 	N1 is N0 + 1,
> 	list_length_non_ac(Xs, N1, N).
>

To avoid endless recursion after the first (and only) solution to
length( -L, +N), while still allowing unrestricted backtracking for
length( -L, -N):

length(Xs, N) :-
	length(Xs, 0, N).

length([], N, N).
length([_|Xs], N0, N) :-
	(
		var( N ), !
	;
		N0 < N
	),
	N1 is N0 + 1,
	length(Xs, N1, N).

----
Andreas Stolcke
International Computer Science Institute	stolcke@icsi.Berkeley.EDU
1957 Center St., Suite 600, Berkeley, CA 94704	(415) 642-4274 ext. 126