有4个参数的foldr?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有4个参数的foldr?相关的知识,希望对你有一定的参考价值。
我正在努力理解为什么这个代码取自haskell.org exercise page typechecks(并作为列表反转函数):
myReverse :: [a] -> [a]
myReverse xs = foldr (x fId empty -> fId (x : empty)) id xs []
我的第一个困惑点是,foldr接受3个参数,而不是4个:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
所以我猜myReverse
相当于:
myReverse xs = foldr ((x fId empty -> fId (x : empty)) id) xs []
但是这不应该工作,因为在lambda中,x
是一个列表元素而不是函数...
这样想吧。每个函数都只接受一个参数。它可能返回另一个函数(接受一个参数)。看起来像多参数调用的东西
f a b c
实际上被解析为
((f a) b) c
也就是说,一系列单参数函数应用程序。一种功能类型
f :: a -> b -> c -> d
可以分解为
f :: a -> (b -> (c -> d))
即返回函数返回函数的函数。我们通常认为它是三个论点的函数。但它可以接受三个以上吗?是的,如果d
恰好是另一种功能类型。
这正是您的fold
示例所发生的情况。作为foldr
的第一个参数传递的函数接受三个参数,这与接受两个参数并返回另一个函数完全相同。现在(简化)类型的foldr
是
(a -> b -> b) -> b -> [a] -> b
但如果你看一下它的第一个参数,你会发现它是三个参数的函数。正如我们所看到的那样,与加入两个参数并返回函数的函数完全相同。所以b
恰好是一种函数类型。因为当应用于三个论点时,b
也是foldr
的回归图
foldr (x fId empty -> fId (x : empty)) id
它是一个函数,现在可以应用于另一个参数
(foldr (x fId empty -> fId (x : empty)) id xs) []
我让你弄明白b
究竟是什么。
首先,命名的变量是残暴的。我总是使用r
作为foldr的reducer函数的第二个参数,作为“递归结果”的助记符。 “empty
”的意思太过分了;最好使用一些中性名称,以便在没有任何先入为主的观念的情况下更容易看到它是什么:
myReverse :: [a] -> [a]
myReverse xs = foldr (x r n -> r (x : n)) id xs []
凭借foldr的定义,
foldr f z (x:xs) === f x (foldr f z xs)
即
myReverse [a,b,c,...,z]
= foldr (x r n -> r (x : n)) id [a,b,c,...,z] []
= (x r n -> r (x : n)) a (foldr (x r n -> r (x : n)) id [b,c,...,z]) []
= (x r n -> r (x : n))
a
(foldr (x r n -> r (x : n)) id [b,c,...,z])
[]
= let { x = a
; r = foldr (x r n -> r (x : n)) id [b,c,...,z]
; n = []
}
in r (x : n)
= foldr (x r n -> r (x : n)) id [b,c,...,z] (a : [])
= foldr (x r n -> r (x : n)) id [b,c,...,z] [a]
= ....
= foldr (x r n -> r (x : n)) id [c,...,z] (b : [a])
= foldr (x r n -> r (x : n)) id [c,...,z] [b,a]
= ....
= foldr (x r n -> r (x : n)) id [] [z,...,c,b,a]
= id [z,...,c,b,a]
我希望这个插图能够更清楚地了解那里发生的事情。额外的参数是由reducer函数预期的,由foldr
推动行动...导致操作相当于
= foldl (
x -> (x : n)) [] [a,b,c,...,z]
事实证明,myReverse
的实现正在使用等价
foldl (flip f) n xs === foldr (x r -> r . f x) id xs n
以上是关于有4个参数的foldr?的主要内容,如果未能解决你的问题,请参考以下文章
Haskell 的 foldr/l 和 Clojure 的 reduce