Ответ 1
Короче: это невозможно. Вы всегда должны каким-то образом разбивать список входных данных, чего вы не можете выполнить, разворачиваясь в одиночку. Вы можете видеть это в своем коде уже. У вас retry (phi f)
, что эквивалентно dropWhile (not . f)
, который рекурсивно потребляет список ввода. В вашем случае рекурсия находится внутри retry
.
Мы можем реализовать filter
с помощью ana
, но функция, переданная в ana
, должна быть рекурсивной, как в
filter1 :: (a -> Bool) -> [a] -> [a]
filter1 p = ana f
where
f [] = Nil
f (x : xs') | p x = Cons x xs'
| otherwise = f xs'
Однако мы можем реализовать фильтрацию с помощью para
без дальнейшей рекурсии:
filter2 :: (a -> Bool) -> [a] -> [a]
filter2 p = cata f
where
f Nil = []
f (Cons x r) | p x = x : r
| otherwise = r
(хотя это вас не интересует).
Итак, почему он работает с cata
, но не с ana
?
- Катаморфизмы представляют собой индуктивную рекурсию, где каждый рекурсивный шаг потребляет по меньшей мере один конструктор. Поскольку каждый шаг занимает только конечное время, вместе это гарантирует, что при потреблении (конечной) структуры данных вся рекурсия всегда заканчивается.
- Анаморфизмы представляют собой коиндуктивную рекурсию, где каждый рекурсивный шаг защищен конструктором. Это означает, что хотя результат может быть бесконечным, каждая часть (конструктор) построенной структуры данных создается за конечное время.
Теперь, как работает filter
: на каждом шаге он потребляет один элемент списка и иногда создает выходной элемент (если он удовлетворяет заданному предикату).
Итак, мы видим, что мы можем реализовать filter
как катаморфизм - мы потребляем каждый элемент списка за конечное время.
Но мы не можем реализовать filter
как анаморфизм. Мы никогда не узнаем, когда filter
создаст новый результат. Мы не можем описать создание следующего выходного элемента, используя только конечное число операций. Например, возьмите filter odd (replicate n 0 ++ [1])
- для выполнения первого элемента 1
требуется выполнить шаги O (n). Таким образом, должна существовать какая-то рекурсия, которая ищет список ввода до тех пор, пока не найдет удовлетворяющий элемент.