A recursive function is tail recursive if the final result of the recursive call is the final result of the function itself. If the result of the recursive call must be further processed (say, by adding 1 to it, or consing another element onto the beginning of it), it is not tail recursive.
With that said, tail recursion is not that useful of a concept in a lazy language like Haskell. The important concept to know in Haskell is guarded recursion, where any recursive calls occur within a dataconstructor (such as
consumed lazily, since it can be evaluated up to the data constructor and the recursive call delayed until needed.
Note that foldl is always tail recursive.
- Brent Yorgey in Haskell-Cafe on Definition of "tail recursive" wrt Folds