В статье "Подключение космического утечка со стрелкой" Лю и Худака утверждается, что это приводит к поведению O (n ^ 2) во время выполнения (для вычисления n-го члена):
successors n = n : map (+1) (successors n)
тогда как это дает нам линейное время:
successors n = let ns = n : map (+1) ns
in ns
. Это утверждение, безусловно, верно, так как я могу легко проверить его с помощью GHCi. Тем не менее, я не могу понять, почему именно, и как совместное использование структуры помогает в этом случае. Я даже пытался выписать оба расширения для вычисления третьего члена.
Вот моя попытка для первого варианта:
successors 1 !! 2
(1 : (map (+1) (successors 1))) !! 2
(map (+1) (successors 1)) !! 1
(map (+1) (1 : map (+1) (successors 1))) !! 1
2 : (map (+1) (map (+1) (successors 1))) !! 1
(map (+1) (map (+1) (successors 1))) !! 0
(map (+1) (map (+1) (1 : map (+1) (successors 1)))) !! 0
(map (+1) (2 : map (+1) (map (+1) (successors 1)))) !! 0
3 : map (+1) (map (+1) (map (+1) (successors 1))) !! 0
3
а второй:
successors 1 !! 2
(let ns = 1 : map (+1) ns in ns) !! 2
(1 : map (+1) ns) !! 2
map (+1) ns !! 1
map (+1) (1 : map (+1) ns) !! 1
2 : map (+1) (map (+1) ns) !! 1
map (+1) (map (+1) ns) !! 0
map (+1) (map (+1) (1 : map (+1) ns)) !! 0
map (+1) (2 : map (+1) (map (+1) ns)) !! 0
3 : map (+1) (map (+1) (map (+1) ns)) !! 0
3
Как вы видите, мои расширения выглядят почти одинаково и, похоже, предлагают квадратичное поведение для обоих. Каким-то образом разделение структуры вступает в последнее определение и использует предыдущие результаты, но выглядит волшебным. Может ли кто-нибудь уточнить?