在下面的代码中,我无法理解累加器参数的发送方式。
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?
答案 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)
在这种情况下,a
是Double
,而b
是Double -> 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
。并且也让n
和sum
上抽象,使用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)