In Mathematica, I create singly linked lists like so:
toLinkedList[x_List] := Fold[pair[#2, #1] &, pair[], Reverse[x]];
fromLinkedList[ll_pair] := List
The examples below give typical results.
One slow example in a length 20 run.
In[18]:= getTimes[whileLength, 20]
Out[18]= {0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.031, \
0.031, 0.047, 0.032, 0.031, 0.031, 3.547, 0.047, 0.031, 0.031, 0.032, \
0.031, 0.031}
I note in passing that the timings are ~10x faster than in the original post, except for the slow cases which are comparable. Not sure what accounts for that difference in ratios.
No slow examples.
In[17]:= getTimes[nestLength, 20]
Out[17]= {0.047, 0.047, 0.062, 0.047, 0.047, 0.062, 0.047, 0.047, \
0.047, 0.063, 0.046, 0.047, 0.047, 0.063, 0.047, 0.046, 0.047, 0.063, \
0.047, 0.047}
One slow example in a length 100 run.
In[19]:= getTimes[whileLength, 100]
Out[19]= {0.031, 0.031, 0.031, 0.032, 0.031, 3.594, 0.047, 0.031, \
0.031, 0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.047, 0.031, \
0.031, 0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.047, 0.031, 0.031, \
0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.031, 0.047, 0.031, \
0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.031, 0.047, 0.031, \
0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.031, 0.047, 0.031, 0.031, \
0.032, 0.031, 0.031, 0.031, 0.032, 0.031, 0.047, 0.031, 0.031, 0.032, \
0.031, 0.031, 0.031, 0.032, 0.031, 0.031, 0.031, 0.032, 0.046, 0.032, \
0.031, 0.031, 0.031, 0.032, 0.031, 0.031, 0.047, 0.031, 0.032, 0.031, \
0.031, 0.031, 0.032, 0.031, 0.047, 0.031, 0.031, 0.031, 0.032, 0.031, \
0.031, 0.031}
Mathematica implements, imperfectly, what is called "infinite evaluation". That is to say, an expression reevaluates until it stops changing. To make this reasonably fast there are various optimizations that attempt to short circuit the process whenever possible.
In some cases this can be tricky to discern (due to an effect similar to hash collisions), and expressions might be needlessly reevaluated. Deeply nested expressions tend to be a worst case for this. We have further code that will often address these even in cases of collisions.
The culprit in this instance is exactly this code that attempts to determine quickly whether an expression requires reevaluation. It is peculiar but possibly a clue (to someone) that this happens at most once in a run inside that While loop. So something happens in the bad cases that prevents recurrence whilst inside the same While.
At one time I was familiar with the reevaluation detection code, having written a chunk of it. But it was rewritten for version 8. So even after seeing this suboptimal behavior in a debugger, it is is something of a mystery to me. About all I can say right now is that I filed a bug report.
As Leonid Shifrin observed, symbols with Attribute of HoldAllComplete are immune to this problem. So using that attribute can be beneficial for this type of code.
Daniel Lichtblau Wolfram Research