Haskell 递推格式及其推广`
我有一个递归模式风格的结构,我想得到一个包括完整结构在内的所有子结构的列表,也就是说,相当于Haskell 递推格式及其推广`,haskell,recursion,functional-programming,Haskell,Recursion,Functional Programming,我有一个递归模式风格的结构,我想得到一个包括完整结构在内的所有子结构的列表,也就是说,相当于tails函数在列表上的作用。我认为可以通过调用para,在每个步骤映射回原始结构,然后将原始结构分别粘贴在前面来实现这一点,但这似乎非常麻烦:(未经测试,如果Haskell不正确,则表示歉意;使用Mu编写,因为我还没有真正理解Base构造) (即,在f=Prim情况下,这是tails,对于其他f情况,这是一种概括) 有更好的方法吗?我意识到这并不是那么糟糕,但是在这一步中恢复“原始”结构的fmap fs
tails
函数在列表上的作用。我认为可以通过调用para
,在每个步骤映射回原始结构,然后将原始结构分别粘贴在前面来实现这一点,但这似乎非常麻烦:(未经测试,如果Haskell不正确,则表示歉意;使用Mu
编写,因为我还没有真正理解Base
构造)
(即,在f=Prim
情况下,这是tails
,对于其他f
情况,这是一种概括)
有更好的方法吗?我意识到这并不是那么糟糕,但是在这一步中恢复“原始”结构的fmap fst a
感觉相当麻烦,而foldMap snd a
是我在使用段落时经常重复的东西(同样地,当使用cata
时,折叠a
,这再次让人觉得它应该是不必要的)。我看不出段落有任何问题。只需在每个cons
步骤中向后翻转头部和尾部即可:
import Data.Functor.Foldable
tails :: [a] -> [[a]]
tails = para (\case Nil -> [[]]; Cons a (as, res) -> (a : as) : res)
为清楚起见,专门用于列表和无递归方案的:
para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f z [] = z
para f z (a:as) = f a as (para f z as)
tails :: [a] -> [[a]]
tails = para (\a as res -> (a : as) : res) [[]]
但是,如果你想更一般一些,那么不太好的para
公式就很方便了:
import qualified Data.Functor.Foldable as Rec (Foldable)
tails :: (Rec.Foldable t, Base t ~ Prim [a]) => t -> [t]
tails as = as : para (\case Nil -> []; Cons a (as, res) -> as : res) as
这通常适用于列表,但您也可以为其他t
-s以及可折叠的实例提供类型实例Base t=Prim[a]
,并使用它们
或者,我们可以保留第一个尾部
定义,但代价是引入可展开
约束:
tails' :: (Unfoldable t, Rec.Foldable t, Base t ~ Prim [a]) => t -> [t]
tails' = para (\case Nil -> [embed Nil]; Cons a (as, res) -> embed (Cons a as) : res)
这还不算太糟糕,因为对于每个项目
无论如何都应该有一个反嵌入
函数的不动点,所以可折叠的
和可展开的
实例自然成对出现。para
确实是这里要使用的正确函数。我把所有东西都放在了一个扩展的例子中如果你想玩的话
我们首先定义不动点Mu
和通常的fold
和para
module Tails where
import Data.Function
newtype Mu f = In { out :: f (Mu f) }
fold :: Functor f => (f a -> a) -> Mu f -> a
fold alg = alg . fmap (fold alg) . out
para :: Functor f => (f (a, Mu f) -> a) -> Mu f -> a
para alg = alg . fmap (\m -> (para alg m, m)). out
然后,我们可以使用para
实现tails
,以及一个额外的Foldable
约束,允许我们使用foldMap
来收集列表monoid中的中间结果:
tails :: (Functor f, Foldable f) => Mu f -> [Mu f]
tails m = m : para (foldMap $ uncurry $ flip (:)) m
我需要一个递归方案的版本,因为我的实际情况不是List
,而是递归方案样式的结构。AIUI递归方案para
是para::Foldable t=>(基t(t,a)->a)->t->a
没有您示例中的b
参数。如果我们用tfa=可能(a,f)
(在这个意义上,Base t
与List
同构,除非我弄错了)但是也可以与其他t
一起调用?Prim
似乎是一个List
特定的东西,而我想要一个适用于非列表数据结构的版本,并且我认为我不必总是定义Base t~Prim[a]
?我考虑的函数不需要任何额外的约束-我已经用一个我认为有效的实现更新了这个问题(但我希望它是一个标准函数,或者至少比我的版本更简洁)这是使用para
时的首选样式吗?我曾想过这样做递归,但我不喜欢m:
,就像我不喜欢fmap fst
——无论哪种方式,它都感觉有点抽象错误。
tails :: (Functor f, Foldable f) => Mu f -> [Mu f]
tails m = m : para (foldMap $ uncurry $ flip (:)) m