Я реализовал сломанную функцию 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
- лучшее, на что я могу надеяться?
Я знаю, что могу использовать складки, но вопрос конкретно о разворачивается.