我使用来自filter
Hackage库的变形函数实现了一个损坏的recursion-schemes
函数:
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
中使用显式递归来实现“重试”,然后使用paramorphism重新实现,所以我以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
的签名看起来非常类似于专门用于列表的apomorphism的第一个参数:
xxapo :: ([a] -> Prim [a] (Either [a] [a])) -> [a] -> [a]
xxapo = apo
([a] -> Either [a] [a]
vs [a] -> Prim [a] [a] (Either [a] [a]
)
所以我想知道是否可以使用apomorphisms或其他广义展开来实现过滤,或者ana . para
是我能期望的最好的?
我知道我可以使用折叠,但问题是关于展开。
答案 0 :(得分:10)
简而言之:这是不可能做到的。你总是必须以某种方式分解输入列表,而单独展开则无法实现。您可以在代码中看到它。您有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])
- 它需要 O(n)步骤来生成第一个元素1
。因此必须有某种递归搜索输入列表,直到找到令人满意的元素。
答案 1 :(得分:1)
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f xs = last $ apo phi ([xs], []) where
phi ([[]], ys) = Cons [] $ Left [ys]
phi ([h:t], ys) | f h = Cons [] $ Right ([t], h:ys)
phi ([h:t], ys) = Cons [] $ Right ([t], ys)
但最后是cata。