累加器参数如何发送到函数?

时间:2018-11-23 21:06:06

标签: haskell functional-programming

在下面的代码中,我无法理解累加器参数的发送方式。

meanFold :: [Double] -> Double
meanFold l = (foldr op unit l) 0 0
    where
        unit :: Double -> Double -> Double
        unit n sum = sum / n
        op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
        (x `op` y ) n sum = y (n+1) (sum +x)

我知道foldr首先将对列表l中的最后一个元素和我选择的单位(即函数“ unit”)应用运算符op。 但是,如何将meanFold的累加器参数发送到单位函数,以使sum和n最初为0?

2 个答案:

答案 0 :(得分:4)

  

我知道foldr首先将操作符op应用于列表中的最后一个元素

我也不完全确定您是否也了解这一点。首先,让我们看一下foldr的类型(专门用于列表)及其定义。

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f e []     = e 
foldr f e (x:xs) = f x (foldr f xs)

在这种情况下,aDouble,而bDouble -> Double -> Double。您知道前者是Double,因为您要折叠一个双打列表。后者是unit的类型,这是您在空情况下返回的内容。

因此,您的foldr在做的是从双精度列表中计算类型为Double -> Double -> Double的函数。在空的情况下,您只需返回函数

unit n sum = sum / n

这是将第二个参数除以第一个参数的函数。那是(/),但其参数已交换。在折叠的每个步骤中,您都可以使用列表的元素来修改该二进制函数。您通过op

对其进行了修改
op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
(x `op` y ) n sum = y (n+1) (sum +x)

我真的不喜欢那里的字母y,因为它看起来像是双字母。让我们将其重写为h。并且也让nsum上抽象,使用lambda使其更容易理解正在发生的事情。

op :: Double -> (Double ->Double ->Double) -> (Double -> Double -> Double)
(x `op` h) = \n sum -> h (n+1) (sum +x)

因此,从列表中得到一个双精度值x,并计算出到目前为止的二进制函数h(最初是unit),我们将计算一个新函数

\n sum -> h (n+1) (sum+x)

类似于上一个函数h,不同之处在于它在应用1之前将x与第一个参数相加,并将h与第二个参数相加。

因此,最后一个折叠的列表[x1, x2, x3]将返回函数

\n sum -> (x1+x2+x3+sum) / (1+1+1+n)

将其应用于两个零时,

  (\n sum -> (x1+x2+x3+sum) / (1+1+1+n)) 0 0 
= (x1+x2+x3+0) / (1+1+1+0)
= (x1+x2+x3) / (1+1+1)

答案 1 :(得分:3)

foldr将从集合的开始到结尾仍然应用该函数,而不是相反的顺序。

foldr的定义使您可以深入了解其工作原理。与foldl的主要区别在于括号的顺序。

More details here