I have the following code:
public static IEnumerable<T> cons<T>(T y, IEnumerable<T> xs)
{
yield return y;
foreach (var x in xs) yield return x;
}
public static bool empty<T>(IEnumerable<T> xs)
{
return !xs.GetEnumerator().MoveNext();
}
public static T head<T>(IEnumerable<T> xs)
{
Debug.Assert(!empty(xs), "Prelude.head: empty list");
var e = xs.GetEnumerator(); e.MoveNext();
return e.Current;
}
// repeat x is an infinite list, with x the value of every element
public static IEnumerable<T> repeat<T>(T x)
{
return cons(x, repeat(x));
}
Why does head(repeat(2)) not work, but if I replace the implementation of repeat with:
// repeat x is an infinite list, with x the value of every element
public static IEnumerable<T> repeat<T>(T x)
{
for(;;) yield return x;
}
it works?
Your first implementation is not tail recursive. The last thing to execute would be the
cons()call, but in order to execute that, it must evaluaterepeat(2). To do that, it must (once again) evaluaterepeat(2). And so on until the stack overflows.Your second implementation creates an enumerator that returns x indefinitely every time it is asked for the next element. No re-entrancy, so no stack overflow.