haskell 中的偏函数应用和折叠

Partial functions application and folds in haskell

我正在尝试通过解决练习和在遇到困难时查看其他解决方案来学习 Haskell。随着函数变得越来越复杂,理解起来有困难。

-- Ex 5: given a list of lists, return the longest list. If there
-- are multiple lists of the same length, return the list that has
-- the smallest _first element_.
--
-- (If multiple lists have the same length and same first element,
-- you can return any one of them.)
--
-- Give the longest function a suitable type.
--
-- Examples:
--   longest [[1,2,3],[4,5],[6]] ==> [1,2,3]
--   longest ["bcd","def","ab"] ==> "bcd"

longest :: (Foldable t, Ord a) => t [a] -> [a]
longest xs = foldl1 comp xs
  where
    comp acc x | length acc > length x = acc
               | length acc == length x = if head acc < head x then acc else x
               | otherwise = x 

因此 foldl1 的工作方式如下 - input: foldl1 (+) [1,2,3,4] output: 10. 据我了解,它需要一个函数将其应用于列表并“折叠”它。我不明白的是 comp acc x 比较 两个列表 并输出更大的长度 list.

我不明白的是longest xs = foldl1 comp xs两个列表如何提供给comp进行比较,什么是foldl1“折叠”,什么是start累加器?

这是我认为我理解的另一种折叠的另一个较短的例子。

foldl -  input: foldl (\x y -> x + y) 0 [1,2,3] output: 6 

它从0开始,从左边开始一个一个地添加每个元素。 foldl 是如何在匿名函数中准确应用 two variables 的。例如,如果匿名函数是 (\x y z-> x + y + z) 它会失败,我还不明白为什么。

我觉得看个符号的例子最容易理解:

foldl k z [a, b, c] = k (k (k z a) b) c

foldl1 k [a, b, c] = k (k a b) c

如您所见,foldl1 只是从前两个参数开始,然后使用 k 将其余参数一个一个地添加到累加器中。

foldl首先将k应用于初始累加器z和第一个元素a,然后将其余元素一个一个地添加。

k 函数只有两个参数,因此您不能为此使用具有三个参数的函数。

我认为您目前对 foldl1/foldl 所做的事情的看法不太准确。正如其他人已经解释的那样 foldl1 f (x:xs) == foldl f x xs 因此列表中的第一个值被视为累加器。

你说 foldl1 (+) list “一个接一个地”取 list 的每个值并计算总和。我认为这个概念具有误导性:实际上你总是取两个值,将它们相加并得到一个中间结果。然后你一遍又一遍地重复,其中一个值是最后一个的中间结果。我非常喜欢下面的插图:

Source

如果您开始考虑这些中间值,那么总是获得较大的值会更有意义。