【发布时间】:2013-08-27 15:10:30
【问题描述】:
我使用来自recursion-schemes Hackage 库的变形实现了一个损坏的filter 函数:
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 是我所希望的最好的?
我知道我可以使用折叠,但问题是关于展开的。
【问题讨论】:
-
我很确定你不能单独使用变形(或变形)来做到这一点。这两种方案表征了生产性核心递归,
filter不一定是生产性的:filter (const False)。 -
我可以使用
ana (const Nil)定义filter (const False) -
你的
filter应该在无限列表上工作吗? -
我现在不在乎。
-
@nponeccop ana- 和 apomorphisms 用于某些函子的余代数。这里我们处理的是列表,所以 colgebra 必须生成一个元素,其余元素的种子,或者一个空列表。由于您需要跳过种子列表中的零个或多个元素,因此您的余代数必然是一个拟态。在您的情况下,这种变形实现了 dropWhile (not.f)
标签: list haskell recursion recursion-schemes corecursion