:- 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 create_list/2. 

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([],0).
compute_length([_|T],N):-
    compute_length(T,TN),
    N is TN+1.

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

% The mylength/3 version is not strictly needed, since the normal
% definition of length is actually reversible, but note that len/2
% when called with L is a variable and N a number is less efficient
% than create_list/2 (which is tail-recursive).
