foldr
接受 2 个参数的函数,但这并不妨碍它接受 3 个参数的函数,前提是该函数具有正确的类型签名。
如果我们有一个函数
g :: x -> y -> z -> w
With
foldr :: (a -> b -> b) -> b -> [a] -> b
我们想要经过的地方g
to foldr
, then (a -> b -> b) ~ (x -> y -> z -> w)
(where ~
是类型相等)。自从->
是右结合的,这意味着我们可以写g
的签名为
x -> y -> (z -> w)
其意义是一样的。现在我们已经生成了一个具有两个参数的函数,该函数返回一个具有一个参数的函数。为了将其与类型统一a -> b -> b
,我们只需要把参数排列起来:
a -> | x ->
b -> | y ->
b | (z -> w)
这意味着b ~ z -> w
, so y ~ b ~ z -> w
and a ~ x
so g
的类型确实必须是
g :: x -> (z -> w) -> (z -> w)
implying
foldr g :: (z -> w) -> [x] -> (z -> w)
这当然不是不可能的,尽管可能性更大。我们的累加器是一个函数,对我来说,这需要用 DiffList 来演示:
type DiffList a = [a] -> [a]
append :: a -> DiffList a -> DiffList a
append x dl = \xs -> dl xs ++ [x]
reverse' :: [a] -> [a]
reverse' xs = foldr append (const []) xs $ []
注意foldr append (const []) xs
返回我们应用的函数[]
反转列表。在本例中,我们为该类型的函数指定了一个别名[a] -> [a]
called DiffList
,但这实际上与写的没有什么不同
append :: a -> ([a] -> [a]) -> [a] -> [a]
这是一个有 3 个参数的函数。