Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 递推格式及其推广`_Haskell_Recursion_Functional Programming - Fatal编程技术网

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