:- module(_,_).

% Meta-logical predicates example -- choosing between two
% implementations based on calling mode (i.e., implementing
% reversibility ''by hand''). 

% A) Simple list length: 

len([],0).
len([_|T],N) :- len(T,TN), N is TN+1.

% B) Choosing between two implementations based on calling mode: 

% With better version also of compute_length/2 (using an 
% accumulating parameter). N both create_list/2 and 
% compute_length/2 are tail recursive.

mylength(Xs,N):- 
    var(Xs),
    integer(N),
    create_list(N,Xs).
mylength(Xs,N):- 
    nonvar(Xs),
    compute_length(Xs,N).

create_list(0,[]).
create_list(N,[_|Xs]):- 
    N > 0,
    N1 is N - 1,
    create_list(N1,Xs).

compute_length(L,N) :-
    compute_length_(L,0,N).

compute_length_([],N,N).
compute_length_([_|T],A,N) :-
    NA is A+1,
    compute_length_(T,NA,N).

% Try:
% ?- len([a,b,c],N).
% ?- len(L,3).
% ?- mylength([a,b,c],N).
% ?- mylength(L,3).
