[Haskell-cafe] Lazy evaluation and tail-recursion

Daniel Fischer daniel.is.fischer at googlemail.com
Wed Mar 16 22:35:09 CET 2011


On Wednesday 16 March 2011 21:44:36, Tillmann Rendel wrote:
> 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.

Mmmm, okay, minor terminology mismatch, then. Makes sense, but is not what 
I'm used to. I'd say it is a tail-call of Cons's second argument, and the 
tail call of map would be Cons, so tail-call is not transitive.

> 
> 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)

s/foo/countdown/

presumably

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

s/foo/countdown'/

> 
> 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.
> 

Formally, not according to the previously mentioned definition, but in 
terms of generated code/runtime behaviour, of course, so

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

I think you're right.

> 
>    Tillmann

Cheers,
Daniel



More information about the Haskell-Cafe mailing list