Я реализовал сломанную функцию filter, используя анаморфизм из recursion-schemes Библиотека Hackage:
import Data.Functor.Foldable
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana $ project . phi f
phi :: (a -> Bool) -> [a] -> [a]
phi f (h : t) | not (f h) = t
phi f l = l
Функция не является достоверной реализацией filter: xfilter odd [1..5] работает, но xfilter odd [0,0] нет. Я попытался реализовать "повторы", используя явную рекурсию в phi, а затем переопределив это с параметризмом, поэтому я закончил с ana . para:
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana . para $ phi where
phi Nil = Nil
phi (Cons h (t, tt)) | f h = Cons h t
phi (Cons h (t, tt)) = tt
Это удовлетворительно, но затем я попытался выразить попытки явно в phi и выполнить их вне:
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana $ project . retry (phi f)
phi :: (a -> Bool) -> [a] -> Either [a] [a]
phi f (h : t) | not (f h) = Left t
phi f l = Right l
retry f x = case f x of
Right x -> x
Left x -> retry f x
Right означает "создать новый элемент" и Left означает "повторить попытку с новым семенем".
Подпись phi начала выглядеть довольно похоже на первый аргумент апоморфизма, специализированный для списков:
xxapo :: ([a] -> Prim [a] (Either [a] [a])) -> [a] -> [a]
xxapo = apo
([a] -> Either [a] [a] vs [a] -> Prim [a] [a] (Either [a] [a])
Так что интересно, возможно ли реализовать фильтрацию с использованием апоморфизмов или других обобщенных разворачиваний, или ana . para - лучшее, на что я могу надеяться?
Я знаю, что могу использовать складки, но вопрос конкретно о разворачивается.