有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?的主要内容,如果未能解决你的问题,请参考以下文章

SML/NJ - 使用 foldr 的一种线长函数

JS常用代码片段-127个常用罗列-值得收藏

foldr 与 foldl(或 foldl')的含义

Haskell 的 foldr/l 和 Clojure 的 reduce

如何使用 foldr/foldl 定义 foldM(如果可能)?

ViewPager开关没有显示片段之间