Это ответ на незаданный вопрос, считайте его длинным комментарием.
(Пожалуйста, уменьшите значение ниже 0, если вы считаете, что он не подходит. Iзатем удалим его.)
Как только вы станете немного опытнее, вы, возможно, больше не захотите видеть, как все расширяется.Вы захотите понять, КАК все это работает, что заменяет вопрос, ПОЧЕМУ это работает;вы больше не получите много, просто наблюдая за тем, как он расширяется.
Способ анализа кода намного проще, чем вы думаете: просто пометьте каждый параметр / переменную как «оцененный» или «неоцененный»или «подлежит оценке», в зависимости от развития их причинных связей.
Два примера:
1.) fibs
Список всех чисел Фибоначчи:
fibs :: (Num a) => [a]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Первые два элемента уже оценены;Итак, пометьте 3-й элемент (который имеет значение 2) как подлежащий оценке, а все остальные - как неоцененные.Третий элемент будет тогда (+) - комбинацией первых элементов fib и хвостовых, которые будут первым и вторым элементом fib, которые уже помечены как оцененные.Это работает с n-м элементом, подлежащим оценке, и с (n-2) -й и (n-1) -й уже оцененными элементами соответственно.
Вы можете визуализировать это по-разному, т.е.:
fibs!!(i+0)
+ fibs!!(i+1)
= fibs!!(i+2)
(fibs)
zipWith(+) (tail fibs)
= (drop 2 fibs)
1 : 1 : 2 : 3 ...
(1 :)1 : 2 : 3 : 5 ...
(1 : 1 :)2 : 3 : 5 : 8 ...
2.) Ваш пример "сито (p: ps) xs"
primes = 2: 3: sieve (tail primes) [5,7..]
where
sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0]
-- or: filter ((/=0).(`rem`p)) t
where (h,~(_:t)) = span (< p*p) xs
In "сито (p: ps)xs ",
- p оценивается,
- ps не оценивается, а
- xs является оцененным бесконечным частично-просеянным списком (не содержит p, но содержит p²), который можно угадать, читая рекурсию и / или признавая, что значения h должны быть простыми.
Sieve должна возвращать список простых чисел после p, так что по крайней мере следующее простое число должнобыть оцененным.
- Следующее простое число будет в списке h, который является списком всех (уже просеянных) чисел k, где p
- t содержит все числа xs выше p².t следует оценивать как ленивый, а не как можно скорее, потому что может даже не быть необходимости оценивать все элементы в h.(Только первый элемент h должен быть оценен.)
Остальной частью определения функции является рекурсия, где следующим xs является t со всеми n * p, просеянными.
В случае foldr, анализ покажет, что «go» определяется только для ускорения времени выполнения, а не читабельности.Вот альтернативное определение, которое легче проанализировать:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (.:) e (x:xs) = x .: (foldr (.:) e xs)
foldr (.:) e [] = e
Я описал его функциональность здесь (без анализа).
Для обучения этого типаанализируя, вы можете прочитать источники некоторых стандартных библиотек;то есть scanl, scanr, unfoldr в источнике из Data.List .