views:

1584

answers:

11

which languages support tail recursion optimization?

+5  A: 

Scheme, Haskell, ...

Dev er dev
+2  A: 

The F# compiler converts directly recursive functions into loops, and all calls in tail position emit code with the CLR .tail opcode, so that you can write e.g. mutually recursive functions that need not consume the stack.

Brian
Believe it or not, tail recursion optimization is a feature of C# as well (albeit one with a lot of restrictions).
Jason Baker
I was under the impression that C# did not implement tail recursion optimization as mentioned in the following book : "Real World Functional Programming by Tomas Petricek"
Alexandre Brisebois
There are enough caveats to using TRO in C# that it shouldn't be something to rely on. But it does make a nice "bonus" optimization in situations where the criteria are met to use TRO.
Jason Baker
+4  A: 

I would assume that tail recursion would be an implementation detail of specific compilers.

James Curran
Some language specs demand that conforming implementions do tail-call optimization.
Brian
Per Wikipedia: "Proper tail recursion optimization is required by the standard definitions of some programming languages, such as Scheme."
slim
To the other commenters: That is beside the point. The question was about languages that *support* it, not about ones that require it.
T.E.D.
It's not beside the point at all. "z is an implementation detail" implies than you can never state "Language x always supports z". But you *can* state "Scheme always supports tail recursion optimization".
slim
(continued) ... a full answer to the question (which we're unlikely to get) would need to be divided into several categories. Languages that always support it, those than cannot ever support it, those that could support it (but no such implementation is known), and those with some implementations.
slim
+3  A: 

Without compiling a comprehensive list of languages:

  • if you need it, it's there
  • if it's not there, you don't need it

Typically the languages that optimise tail recursion are languages in which tail recursion is the commonest way to achieve iteration.

In Scheme, you iterate by recursing. Therefore, the language standard requires tail recursion optimisation - otherwise iterating over very long lists would be impossible.

In most procedural languages, you iterate with for or while - tail recursion optimization is no help there. In languages that provide these constructs, you wouldn't typically choose to use recursion for problems that could be solved with tail-recursion.

slim
+3  A: 

64-bit .Net supports tail recursion optimization, but you shouldn't make dependencies on it: Tail Call JIT conditions.

The 2nd part of that post goes into much more detail: Enter, Leave, Tailcall Hooks Part 2: Tall tales of tail calls

Jason Baker
note that as of the VS 2010 release you can take a dependency on the x64 JIT respecting a tail call directive but not that it will always be _quick_
ShuggyCoUk
+2  A: 

SML and OCaml also

Dylan also asks the implementatin to be properly tail recusive.

One interesting point though is that simply adding a type signature to a function could render a function non-tail recursive.

define function count(i :: <integer>)
  if (i == 0)
    i ;
  else
    count(i - 1) ;
  end
end

is tail recusive, but

define function count(i :: <integer>) => (sum :: <integer>)
  if (i == 0)
    i ;
  else
    count(i - 1) ;
  end
end

is not. The reason is that adding the signature to the function requires the compiler to add code after the recursive call to check the type signature. This makes the function call no longer tail recursive.

Pierre
A: 

This isn't a laguage question, it's a compiler question. I don't know of any language that has some syntactic element in it that prevents a compiler from optimizing that way.

For example, I think any compiler that uses the gcc back end supports tail recursion elimination at -O3

T.E.D.
Technically it isn't a language question but a compiler question. But when we're talking about languages loosely we tend to associate the standard compiler closely with the language. So it's like Java does not support while Haskell supports (qualifier: using their respective standard compilers).
blizpasta
I don't think "standard compiler" is a healthy concept to use - even with languages which probably won't ever have two implementations (e.g. Perl). Targeting a specific compiler is like writing IE-only HTML.
slim
There is no such thing as a "standard compiler" for C, Fortran, Ada, Lisp, Pascal, Cobol, or most other languages in existance.
T.E.D.
Yes there is no such thing as "standard compiler" for some languages. I should have qualified my comment instead of generalizing.
blizpasta
Java (because of the JVM) prevents doing this efficiently
Claudiu
Not sure where you got that Claudiu. I did find a reference to statically compiled Java having a bit of trouble with it in some weird cases, but even that said JIT-compiled code would work as designed.
T.E.D.
Scheme requires tail call optimization: this is part of the language. If a Scheme compiler doesn't optimize it, then it's not a Scheme compiler.
Adam Goode
*a lot* of languages demand that compilers and interpreters optimize tail calls.
Lajla
+4  A: 

Scheme, Lua, Standard ML, Mozart/Oz.

These languages promise that such code

return some_function(params);

reuses current stack frame.

lazyden
+3  A: 

Erlang is another.

Nicholas Mancuso
+2  A: 

LOGO supports tail recursion optimization.

JohnnySoftware
+1  A: 

Perl with goto systax:

From perldoc:

"The goto-&NAME form is quite different from the other forms of goto. In fact, it isn't a goto in the normal sense at all, and doesn't have the stigma associated with other gotos. Instead, it exits the current subroutine (losing any changes set by local()) and immediately calls in its place the named subroutine using the current value of @. This is used by AUTOLOAD subroutines that wish to load another subroutine and then pretend that the other subroutine had been called in the first place (except that any modifications to @ in the current subroutine are propagated to the other subroutine.) After the goto, not even caller will be able to tell that this routine was called first."

Thushan