Chapter 8 of The RealWorldHaskell
globToRegex' (c:cs) = escape c ++ globToRegex' cs
This function is not tail recursive and it says that the answer relies on Haskell non-strict(lazy) evaluation strategy. The (++)
operator's simple definition lies in the following and it's not tail recursive.
(++) :: [a] -> [a] -> [a] (x:xs) ++ ys = x : (xs ++ ys) [] ++ ys = ys
In a strict language, if we evaluate
"foo" ++ "bar"
, the entire list is constructed, then returned. Non-strict evaluation defers much of the work until it is needed.If we demand an element of the expression
"foo" ++ "bar"
, the first pattern of the function's definition matches, and we return the expressionx : (xs ++ ys)
. Because the(:)
constructor is non-strict, the evaluation ofxs ++ ys
can be deferred: we generate more elements of the result at whatever rate they are demanded. When we generate more of the result, we will no longer be usingx
, so the garbage collector can reclaim it. Since we generate elements of the result on demand, and do not hold onto parts that we are done with, the compiler can evaluate our code in constant space.
(Emphasis added.)
The explanation above in bold is something essential to Haskell, But
- How can we comprehend that?
- What happend in the underlying?
- "
x:(xs ++ ys)
will evalute in constant space", how? It sounds what tail recursion does!
x
when generating the nextxs
on demand. – sarnold