推广折叠使得它变得足够表达以定义任何有限递归?

时间:2018-03-06 19:22:32

标签: haskell functional-programming generic-programming fold proof

所以,有一个被称为"折叠"的通用属性的东西,正好说明:

g [] = i; g (x:xs) = f x (g xs)< => g = fold f i

但是,正如您现在可能的那样,dropWhile等极少数情况下,除非您将其概括为,否则无法将其重新定义为fold f i

最简单但最明显的推广方法是重新定义通用属性:

g' y [] = j y; g' y (x:xs) = h y x xs (g' y xs)< => g' y = fold (?) l

此时我可以做出我的假设:我假设存在某种函数p :: a -> b -> b,它将满足等式g' y = fold p l。让我们试着用普遍属性帮助解决给定的方程式,最开始提一下:

  • g' y [] = j y = fold p l [] = l => j y = l
  • g' y (x:xs) = h y x xs (g' y xs) = fold p l (x:xs) = p x (fold p l xs) = p x (g' y xs) =>让rs = (g' y xs) h y x xs rs = p x rs,这是错误的xs从左边自由发生,因此不能保持平等。

现在让我试着解释我提出的结果并提出问题。 我发现问题是xs 出现为未绑定的变量;它适用于各种情况,包括上面提到的dropWhile。这是否意味着可以解决方程的唯一方法是通过"扩展" rs对一对(rs, xs)?换句话说,fold累积到元组而不是单个类型(忽略元组本身是单一类型的事实)?有没有其他方法可以概括绕过配对?

1 个答案:

答案 0 :(得分:4)

就像你说的那样。通用属性表示g [] = i; g (x:xs) = f x (g xs) iff g = fold f i。这不能适用于dropWhile的直接定义,因为可能f :: a -> [a] -> [a]不仅取决于当前折叠步骤中的元素和累计值,还取决于左边的整个列表后缀过程(用你的话说,“xs emerg [es]作为一个未绑定的变量”)。可以做的是扭转dropWhile,以便对列表后缀的这种依赖性在累积值中变得明显,无论是通过元组 - 参见。 dropWhilePair from this questionf :: a -> ([a], [a]) -> ([a], [a]) - 或函数 - 如chi's implementation ...

dropWhileFun = foldr (\x k -> \p -> if p x then k p else x : k (const False)) (const [])

...与f :: a -> ((a -> Bool) -> [a]) -> ((a -> Bool) -> [a])

在一天结束时,普遍属性就是这样 - 一个关于foldr的基本事实。并非所有递归函数都可以通过foldr立即表达,这并非偶然。实际上,你的问题所带来的元组解决方法直接反映了paramorphism的概念(有关它们的解释,请参阅What are paramorphisms? and its exquisite answer by Conor McBride)。从表面看,同构性是对同态的概括(即简单的折叠);然而,就catamorphisms而言,实现paramorphisms只需要轻微的扭曲。 (关于这方面的其他技术评论可以在Categorical Programming With Inductive and Coinductive Types, Varmo Vene's PhD thesis的第3章中找到。)