There is no significant performance difference between the two approaches.
Both these methods can however give a quite significant overhead if used extensively. The problem is that both these approaches will copy all the strings into a new string.
This simple program:
Code: Select all
clauses
run() :-
N = 1000,
S = list1(N),
stdio::write(S).
class predicates
list1 : (unsigned N) -> string Tree.
clauses
list1(0) = "0" :-
!.
list1(N) = T2 :-
T1 = list1(N-1),
T2 = string::format("%, %", T1, N).
It creates a string of the form "0, 1, 2, ..., 1000". But doing so it creates 1000 strings of increasing length each time copying to previous string into the new one. As result the algorithm is O(N^2).
The "right" way to do this is by using a stream instead of creating strings on the fly:
Code: Select all
class predicates
list2 : (unsigned N) -> string Tree.
clauses
list2(N) = S:getString() :-
S = outputStream_string::new(),
list2b(S, N).
class predicates
list2b : (outputStream S, unsigned N).
clauses
list2b(S, 0) :-
!,
S:write("0").
list2b(S, N) :-
list2b(S, N - 1),
S:writef(", %", N).
To see that this really matters I have run the following little test:
Code: Select all
clauses
run() :-
profileTime::init(),
foreach N in [100, 1000, 10000] do
C1 = convert(profileTime::costName, string::format("list1(%)", N)),
profileTime::start_pr(C1),
_S1 = list1(N),
profileTime::stop_pr(C1),
C2 = convert(profileTime::costName, string::format("list2(%)", N)),
profileTime::start_pr(C2),
_S2 = list2(N),
profileTime::stop_pr(C2)
end foreach,
profileTime::printAndReset().
Which gives results as shown in the image. I guess it is obvious that
list1 have a problem compared to
list2.