有4个参数的foldr?

问题描述 投票:2回答:2

我正在努力理解为什么这个代码取自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是一个列表元素而不是函数...

haskell
2个回答
4
投票

这样想吧。每个函数都只接受一个参数。它可能返回另一个函数(接受一个参数)。看起来像多参数调用的东西

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究竟是什么。


2
投票

首先,命名的变量是残暴的。我总是使用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 (\n x -> (x : n)) [] [a,b,c,...,z]

事实证明,myReverse的实现正在使用等价

foldl (flip f) n xs  ===  foldr (\x r -> r . f x) id xs n
© www.soinside.com 2019 - 2024. All rights reserved.