Haskell中存在不同类型的折叠,例如foldl
和foldr
。
我读到了以下平衡折叠:
balanced_fold::(e->e->e)->e->[e]->e
balanced_fold _ b [] =b
balanced_fold f b l@(_:_:_)=
let
len= length l
(half1,half2)=
divide_list (div len 2) l
value1=balanced_fold f b half1
value2=balanced_fold f b half2
in
f value1 value2
divide_list :: Int-> [a]->([a],[a])
divide_list _ [] =([],[])
divide_list n (x:xs)
| n==0 =([],x:xs)
| otherwise =
let (half1,half2)=
divide_list (n-1) xs
in
(x:half1, half2)
根据定义,当列表只包含一个元素[x]
时,输出将为x
。
我的问题是:当一个列表只包含一个元素时,我们不需要使用基值来处理这个元素吗?
我们知道,foldr
和foldl
确实使用基值来处理列表中的元素,即使只有一个元素。
foldl::(v->e->v)->v->[e]->v
foldl _ base [] =base
foldl f base (x:xs)=
let newbase =f base x in
foldl f newbase xs
答案 0 :(得分:3)
我希望这能回答你的问题:
首先让我们修复你的功能:
balanced_fold :: (e -> e -> e) -> e -> [e] -> e
balanced_fold _ b [] = b
balanced_fold f b [a] = f b a
balanced_fold f b l =
let len= length l
(half1,half2)= divide_list (div len 2) l
value1=balanced_fold f b half1
value2=balanced_fold f b half2
in f value1 value2
你可以看到我添加了一个处理长度1(缺失的部分)列表的案例 - 我希望你现在看到基础案例的位置
你所拥有的问题是,它只有一个元素的列表没有匹配的情况 - 即使你要删除(_:_:_)
(你真的不需要)你会结束在divide_list
始终为您提供类似([],[x])
并且[x]
会在同一案例中递归 - 的情况下 - 这就是为什么您需要额外案例来处理这种情况的原因
这是一个快速测试会话,看它是否有效:
λ> balanced_fold (+) 0 []
0
λ> balanced_fold (+) 0 [1]
1
λ> balanced_fold (+) 0 [1..4]
10
λ> balanced_fold (+) 0 [1..5]
15
我觉得似乎没问题
注意当你的操作是 associative 并且你有某种 base / 中性元素时,这一切只能起作用(对于这个操作) )。
所有这些已经有一个课程Monoid
,所以你也可以这样写:
import Data.Monoid
balanced_fold :: Monoid e => [e] -> e
balanced_fold [] = mempty
balanced_fold [a] = a
balanced_fold l =
let len = length l
(half1,half2) = divide_list (div len 2) l
value1 = balanced_fold half1
value2 = balanced_fold half2
in value1 `mappend ` value2
看到它只是
f
现在是mappend
b
只是mempty
现在申请这个例子有点难看:
λ> balanced_fold (map Sum [1..4])
Sum {getSum = 10}
但这只是因为数字可能有多个monoid。