"For example, a function not being tail-recursive despite you believing it to be."
In haskell, I don't think tail recursion is nearly as important because of laziness. While one computation is adding more to the "stack", another is consuming.
foldr, for instance, is not tail-recursive. It can return (partial) results given infinite input with constant memory.
Of course, tail recursion is still important in the places that strictness is important. It's just not quite as fundamental in a language where laziness is the default.
I think there are ways to tell if the TCO has been used, regardless. That's not a property of the type system, or even the language, but the implementation. If nothing else, the profiler should tell you quickly.
In haskell, I don't think tail recursion is nearly as important because of laziness. While one computation is adding more to the "stack", another is consuming.
foldr, for instance, is not tail-recursive. It can return (partial) results given infinite input with constant memory.
Of course, tail recursion is still important in the places that strictness is important. It's just not quite as fundamental in a language where laziness is the default.
I think there are ways to tell if the TCO has been used, regardless. That's not a property of the type system, or even the language, but the implementation. If nothing else, the profiler should tell you quickly.