与大多数其他语言相比,Haskell 中的类型更重要且信息量更大。当您不了解 Haskell 时,最好的第一步是考虑类型。所以让我们这样做。我们将启动 ghci 并输入:
Prelude> let mult_add d s = d + 10 * s
现在询问它的类型:
Prelude> :t mult_add
mult_add :: Num a => a -> a -> a
也就是说, mult_add 接受 ana和 another a,并返回 an a,附带条件a是类的实例Num(以便您可以将它们相加和相乘)。
你被要求使用foldr来编写这个函数,所以让我们看看它的类型:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
这看起来有点吓人,所以让我们分解一下。第一部分,(a -> b -> b)告诉我们foldr需要两个变量的函数,a和b。好吧,我们已经有了其中之一 - 它是mult_add. 那么如果我们mult_add作为第一个参数输入会发生foldr什么呢?
Prelude> :t foldr mult_add
foldr mult_add :: Num b => b -> [b] -> b
好的!我们现在有一个函数,它接受 ab和 a [b](bs 的列表)并返回 a b。您尝试编写的函数需要在0给定空列表时返回,因此让我们尝试将空列表提供给它,并为其余参数提供一些不同的值:
Prelude> foldr mult_add 10 []
10
Prelude> foldr mult_add 5 []
5
嘿,这很有趣。如果我们给它输入数字x和空列表,它只会返回x(注意:这总是正确的foldr。如果我们给它初始值x和空列表[],它会返回x,无论我们使用什么函数代替mult_add。)
因此,让我们尝试将其0作为第二个参数提供:
Prelude> foldr mult_add 0 []
0
这似乎行得通。现在如果我们给它提供列表[1,2,3,4]而不是空列表呢?
Prelude> foldr mult_add 0 [1,2,3,4]
4321
好的!所以它似乎工作。现在的问题是,为什么它会起作用?理解的诀窍foldr是在 的每个元素之间foldr f x xs插入函数,另外放在 列表的末尾,并从右侧收集所有内容(这就是为什么它被称为右折叠)。因此,例如:fxsx
foldr f 0 [1,2,3] = 1 `f` (2 `f` (3 `f` 0))
其中反引号表示我们正在使用中缀形式的函数(所以它的第一个参数是左边的那个,第二个参数是右边的那个)。在您的示例中f = mult_add,您有 将其第二个参数乘以 10 并将其添加到第一个参数:
d `mult_add` s = d + 10 * s
所以你有了
foldr mult_add 0 [1,2,3] = 1 `mult_add` (2 `mult_add` (3 `mult_add 0))
= 1 `mult_add` (2 `mult_add` 3)
= 1 `mult_add` 32
= 321
这符合您的期望。为了确保您理解这一点,请弄清楚如果您mult_add以相反的方式定义会发生什么,即
mult_add d s = 10 * d + s