I was playing with permutation
in a couple of programs and stumbled upon this little experiment:
Permutation method 1:
permute([], []).
permute([X|Rest], L) :-
permute(Rest, L1),
select(X, L, L1).
Permutation method 2:
permute([], []).
permute(L, [P | P1]) :-
select(P, L, L1),
permute(L1, P1).
Permutation method 3 (use the built-in):
permute(L, P) :- permutation(L, P).
I understand that it's good practice to use tail recursion, and generally using built-ins is supposed to be efficient. But when I run the following:
time(findall(P, permute([1,2,3,4,5,6,7,8,9], P), L)).
I got the following results, which are relatively consistent across several runs:
Method 1:
% 772,064 inferences, 1.112 CPU in 2.378 seconds (47% CPU, 694451 Lips)
Method 2:
% 3,322,118 inferences, 2.126 CPU in 4.660 seconds (46% CPU, 1562923 Lips)
Method 3:
% 2,959,245 inferences, 1.967 CPU in 4.217 seconds (47% CPU, 1504539 Lips)
So the non-tail recursive method is quite significantly more real-time efficient.
Is a particular recursion type generally more real time efficient, all other things being equal (I know that's not always a simple premise)? What this experiment tells me is that I may not want to be always striving for tail recursion, but I may need to do a performance analysis first, then weigh performance benefit against other benefits that tail recursion does have.