globToRegex' (c:cs) = escape c ++ globToRegex' cs
这个函数不是尾递归的,它表明答案依赖于Haskell的非严格(懒惰)求值策略。 (++)
运算符的简单定义如下所示,并且它不是尾递归的。
(++) :: [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.
(强调添加。)
上面加粗的解释对于Haskell非常重要,但是:
- 我们如何理解它?
- 底层发生了什么?
- "
x:(xs ++ ys)
将在常数空间中评估",为什么?听起来像尾递归做的事情!
xs
时丢弃x
。 - sarnold