I implemented a broken filter
function using an anamorphism from recursion-schemes
Hackage library:
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
The function is not a faithful implementation of filter
: xfilter odd [1..5]
works, but xfilter odd [0,0]
doesn't. I tried to implement "retries" by using explicit recursion in phi
and then reimplemented that with a paramorphism, so I ended with 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
This is satisfactory, but I then tried to express retries explicitly in phi
and perform them outside:
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
means 'produce a new element' and Left
means 'retry with a new seed'.
The signature of phi
started to look pretty similar to the first argument of apomorphism specialized for lists:
xxapo :: ([a] -> Prim [a] (Either [a] [a])) -> [a] -> [a]
xxapo = apo
([a] -> Either [a] [a]
vs [a] -> Prim [a] [a] (Either [a] [a]
)
So I wonder is it possible to implement filtering using apomorphisms or other generalized unfolds, or ana . para
is the best I can hope for?
I know I can use folds, but the question is specifically about unfolds.
filter
need not be productive:filter (const False)
. – Predikantfilter (const False)
usingana (const Nil)
– Kronosfilter
work on infinite lists? – Predikant