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
的每个值并计算总和。我认为这个概念具有误导性:实际上你总是取两个值,将它们相加并得到一个中间结果。然后你一遍又一遍地重复,其中一个值是最后一个的中间结果。我非常喜欢下面的插图:
如果您开始考虑这些中间值,那么总是获得较大的值会更有意义。
我正在尝试通过解决练习和在遇到困难时查看其他解决方案来学习 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
的每个值并计算总和。我认为这个概念具有误导性:实际上你总是取两个值,将它们相加并得到一个中间结果。然后你一遍又一遍地重复,其中一个值是最后一个的中间结果。我非常喜欢下面的插图:
如果您开始考虑这些中间值,那么总是获得较大的值会更有意义。