所以,有一个被称为"折叠"的通用属性的东西,正好说明:
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
累积到元组而不是单个类型(忽略元组本身是单一类型的事实)?有没有其他方法可以概括绕过配对?
答案 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 question,f :: 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章中找到。)