[Haskell-cafe] Lazy evaluation and tail-recursion

Tillmann Rendel rendel at informatik.uni-marburg.de
Wed Mar 16 21:44:36 CET 2011


Hi,

Daniel Fischer wrote:
>>    data EvaluatedList a
>>
>>       =  Cons a (List a)
>>
>>       |  Empty
>>
>>     type List a
>>
>>       = () ->  EvaluatedList a
>>
>>     map :: (a ->  b) ->  (List a ->  List b)
>>     map f xs
>>
>>       = \_ ->  case xs () of
>>
>>                 Cons x xs  ->   Cons (f x) (\_ ->  map f xs ())
>>                 Empty      ->   Empty
>>
>> Here, the call to map is more visibly in tail position.
>
> According to the definition of tail recursion that I know, that's not tail
> recursive.

My point is that the call to map is in tail position, because it is  
the last thing the function (\_ -> map f xs ()) does. So it is not a  
tail-recursive call, but it is a tail call.

Of course, (\_ -> map f xs ()) does not occur literally in the Haskell  
implementation of map, but the runtime behavior of the Haskell  
implementation of map is similar to the runtime behavior of the code  
above in a strict language.


Let's look at the following code:

   countdown n = if n == 0 then 0 else foo (n - 1)

   if' c t e = if c then t else e
   countdown' n = if' (n == 0) 0 (foo (n - 1))

countdown is clearly tail-recursive. Because of Haskell's non-strict  
semantics, countdown and countdown' have the same runtime behavior. I  
therefore submit that countdown' is tail-recursive, too.


So I think that in a non-strict language like Haskell, we need to  
define "tail position" semantically, not syntactically.

   Tillmann




More information about the Haskell-Cafe mailing list