Writing functional notation is often quite costly in terms of auxiliary space consumption. This is particularly critical for canonical writing of lists.
First consider the size of the output: Whereas the usual ignore_ops(false)
writing requires at least 2n+1 characters for a list of length n as in [1,2,3]
, canonical writing requires at least 7n+2 as in '.'(1,'.'(2,'.'(3,[])))
. (Added:) There is no way to change the output, as it is defined like that. However, there is ample room for improvement during writing:
And now consider the auxiliary space required to write the output: Writing lists with square brackets does not require any auxiliary space proportional to the length of the list. A naive canonical writing requires space proportional to the length of the list to represent the stack of indentations.
How to write a list canonically without that overhead?
Here is a simple test to check what happens in your system.
First, reduce the maximal virtual memory size to reduce your waiting time, some 180M-ish works for me.
$ ulimit -v -180000
With
nat_sx(N0, s(X)) :-
N0 > 0,
N1 is N0-1, nat_sx(N1,X).
nat_sx(0, 0).
?- open('/dev/null',write,Null),
length(_,I), N is 10^I, nat_sx(N,SX),
( Res=unwritten ; write_canonical(Null,SX) ).
SICStus and SWI alike now abort within write_canonical(Null, SX)
. It would be expected that they rather abort at some point in nat_sx/2
. A direct comparison for lists is not possible, as SWI's write_canonical/1
always uses square brackets.
_SX
instead ofSX
to hide the binding at the toplevel. SICStus does this by default. SWI can be instructed to do so by using?- set_prolog_flag(toplevel_print_anon, false).
upfront. – repeat