haskell - 累加器参数如何发送给函数?

标签 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 的累加器参数是如何传递给 unit 函数的,使得 sum 和 n 初始为 0?

最佳答案

I understand that foldr will firstly apply the operator op for the last element in the list

我也不完全确定你是否理解这一点。首先让我们看一下 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 因为你正在折叠一个 double 列表。后者是 unit 的类型,也就是你在空的情况下返回的。

所以你的 foldr 正在做的是从 double 列表中计算 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,因为它使它看起来像 double 。让我们将其重写为 h。并且让我们对 nsum 进行抽象,使用 lambda 更容易理解正在发生的事情。

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

因此,给定列表中的 double 值 x,以及到目前为止计算的二进制函数 h(最初是 unit),我们是计算一个新函数,

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

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

所以最后对于一个列表 [x1, x2, x3] 那个 fold 会返回函数,

\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)

关于haskell - 累加器参数如何发送给函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53452943/

相关文章:

Haskell 函数将操作递归地应用于参数

functional-programming - letrec 有什么好处?

f# - 在F#的此示例中避免突变

java - 如何跳过java流中的连续元素?

Scala unFlatMap

haskell - IO 上的 mapM 产生无限输出

Haskell 类型类

haskell - 使用 Haskell 进行无监督聚类

haskell - cons操作cons元素是从右到左吗?

java - 如何给 groovy 闭包参数一个类型