Каноническая реализация length :: [a] -> Int
:
length [] = 0
length (x:xs) = 1 + length xs
что очень красиво, но страдает от переполнения стека, поскольку использует линейное пространство.
Хвостовая рекурсивная версия:
length xs = length' xs 0
where length' [] n = n
length' (x:xs) n = length xs (n + 1)
не страдает этой проблемой, но я не понимаю, как это может работать в постоянном пространстве на ленивом языке.
Разве среда выполнения не накапливает многочисленные (n + 1)
переходы по мере продвижения по списку? Разве эта функция Haskell не должна занимать пространство O (n) и приводить к переполнению стека?
(если важно, я использую GHC)