Tail recursion is iteration in any decent functional language implementation. Here's an example using GHC Haskell. A simple program to add a sequence of numbers. It begins as the composition of several recursive functions:
import qualified Data.Vector as U
main = print (U.sum (U.enumFromTo 1 (10000000 :: Int)))
Which the compiler optimizes into a single tail recursive function (in a source-to-source transformation):
loop x y = case y <= y 10000000 of
False -> x
True -> loop (x + y) (y + 1)
This recursive function is then compiled into a straight forward loop:
loop:
.Lc216:
cmpq $10000000,%rsi
jle .Lc219
movq %r14,%rbx
movq (%rbp),%rax
jmp *(%rax)
.Lc219:
addq %rsi,%r14
incq %rsi
jmp loop
Or with the GHC LLVM backend, additional optimizations are applied to the imperative representation of the program:
loop:
leaq 1(%rsi), %rax
addq %rsi, %r14
cmpq $10000001, %rax
jge .LBB1_5
addq $2, %rsi
addq %rax, %r14
test: # %tailrecurse
cmpq $10000001, %rsi
jl loop
Note how the tail recursive label is tagged.
So we had a pipeline of recursive functions, which were compiled to a single tail recursive function, which was compiled to a single imperative loop using no stack. And 8 instructions in the end.
And that is why both function composition, and recursion, are extremely efficient in good, optimizing function languages.