我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]
对[a] -> Prim [a] [a] (Either [a] [a]
)
所以我想知道是否有可能使用同构或其他广义展开来实现过滤,或者ana . para
是我所希望的最好的?
我知道我可以使用折叠,但问题是专门关于展开的。