haskell - 如何使用递归方案更新结构?

标签 haskell recursion-schemes

在递归方案中,如何使用类型定义构造一些东西,如 (Recursive t, CoRecursive t) -> t -> ? -> t
我尝试使用递归方案来更新节点。以列表为例,我可以想出两种方法:

update :: [a] -> Natural -> a -> [a]
update = para palg where
  palg Nil _ _ = []
  palg (Cons a (u, _)) 0 b = b : u
  palg (Cons a (u, f)) n b = a : f (n-1) b

update' :: [a] -> Natural -> a -> [a]
update' = c2 (apo acoalg) where
  c2 f a b c = f (a,b,c)
  acoalg ([], _, _) = Nil
  acoalg (_:as , 0, b) = Cons b $ Left as
  acoalg (a:as , n, b) = Cons a $ Right (as, n-1, b)

但是,这两种实现都很好。在这两个实现中,ListF 的构造函数和 []出现在等式两边。而且这个定义似乎不是唯一的。有没有更好的方法来使用递归方案执行列表更新?

最佳答案

递归方案是灵活的方法。您还可以实现自己的变体。

(重用cata)

zipo :: (Recursive g, Recursive h) => (Base g (h -> c) -> Base h h -> c) -> g -> h -> c
zipo alg = cata zalg
 where
  zalg x = alg x <<< project

update :: forall a. [a] -> Natural -> a -> [a] 
update xs n a = zipo alg n xs 
  where
    alg :: Maybe ([a] -> [a]) -> ListF a [a] -> [a]
    alg _ Nil = []
    alg Nothing (Cons y ys) = a:ys
    alg (Just n') (Cons y ys) = y:(n' ys)

你也可以实现一些并行版本,比如
zipCata :: (Recursive g, Recursive h) => ((g -> h -> r) -> Base g g -> Base h h -> r) -> g -> h -> r
zipCata phi x y = phi (zipCata phi) (project x) (project y)

update' :: forall a. [a] -> Natural -> a -> [a]    
update' xs n a = zipCata alg n xs 
  where
    alg :: (Natural -> [a] -> [a]) -> Maybe Natural -> ListF a [a] -> [a]
    alg _ _ Nil = []
    alg _ Nothing (Cons _ ys) = a:ys
    alg f (Just n) (Cons y ys) = y:(f n ys)

两种变体(也作为您的)将得到相同的结果

PS。我讨厌 SO 上的代码示例方法

关于haskell - 如何使用递归方案更新结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58224467/

相关文章:

parsing - Trifecta 中的自定义状态

haskell - 证明展开的融合定律

python - 在 Python 中高效地生成词典系列

haskell - 我如何使用递归方案来表达 Haskell 中的概率分布

haskell - 模式匹配数据类型及其在 Haskell 中的嵌套名称

haskell - 为什么这个类型不检查?

javascript - 如何在 GHCJS 上将未装箱的 Vector 转换为 JS TypedArray?

scala - 优化一个免费的 Monad

haskell - 是否可以用递归方案比较两棵树?

javascript - 折叠中使用的模运算符的单位元