Sml 使用foldl/foldr插入函数
我一直在研究一个单独的函数,该函数返回一个列表,在列表l的每个k个元素之后插入元素x(从 列表的末尾)。例如,separate(1,0[1,2,3,4])应该返回[1,0,2,0,3,0,4]。我完成了该功能,并使其按如下方式工作:Sml 使用foldl/foldr插入函数,sml,ml,mosml,Sml,Ml,Mosml,我一直在研究一个单独的函数,该函数返回一个列表,在列表l的每个k个元素之后插入元素x(从 列表的末尾)。例如,separate(1,0[1,2,3,4])应该返回[1,0,2,0,3,0,4]。我完成了该功能,并使其按如下方式工作: fun separate (k: int, x: 'a, l: 'a list) : 'a list = let fun kinsert [] _ = [] | kinsert ls 0 = x::(kinsert ls k)
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let
fun kinsert [] _ = []
| kinsert ls 0 = x::(kinsert ls k)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
我现在正在尝试使用foldl/foldr简化函数,而不使用任何递归,但我似乎无法使它正常工作。关于如何实现这一点,有什么提示/建议吗?谢谢大家! 这些或多或少是我在尝试使用
foldl
/foldr
编写函数时的想法:
fun separate (k, x, L) =
let fun kinsert (y, ys) = ...
in foldr kinsert [] L
end
/foldl
从构成最终结果的逻辑中抽象出列表递归foldr
- 首先,绘制一个与原始程序结构非常相似的函数,但其中使用了
,而foldr
不是递归函数,而是指定给kinsert
的函数:foldr
这不是绝对必要的fun separate (k, x, L) = let fun kinsert (y, ys) = ... in foldr kinsert [] L end
也可以是匿名的kinsert
- 您正在使用一个内部助手函数
,因为您需要一个kinsert
(k
)的副本,每次它达到0时,您会逐渐递减并重置为i
。因此,k
吐出的列表相当于折叠的累积变量,kinsert
以大致相同的方式临时累积(偶尔重置)i
- 更改
的累加变量,为kinsert
腾出空间:i
现在折叠的结果变成了一个列表,这导致了两个问题:1)我们只想暂时积累i,但这是最终结果的一部分。可以通过使用fun separate (k, x, L) = let fun kinsert (y, (i, xs)) = ... in foldr kinsert (?, []) L end
丢弃它来避免这种情况。2) 如果结果现在是一个元组,我不确定将什么作为第一个#2(foldr…
来代替I
?
- 由于
是一个单独的函数声明,因此可以使用模式匹配和多个函数体:kinsert
fun separate (k, x, L) = let fun kinsert (y, (0, ys)) = ... | kinsert (y, (i, ys)) = ... in ... foldr kinsert ... L end
<> L> >P>你原来的代码> KySert < /C>偏离了一个折叠方式的递归模式:在中间模式中,当<代码> 匹配<代码> 0 > /代码>时,你并没有砍掉一个元素“<代码> ls <代码> >,否则折叠会迫使你。因此,您的
0
案例看起来与原始案例略有不同;你可能会遇到一个错误
foldr
实际上首先访问列表中的最后一个元素,此时i
将具有其初始值,其中对于原始kinsert
,i
的初始值将在您位于第一个元素时foldl
还是foldr
,您将遇到不同的问题:foldl
将反转列表,但按正确的顺序处理项目foldr
将保持列表顺序正确,但当k
不划分L
的长度时,将创建不同的结果fun separate (k, x, L) =
let fun kinsert (y, (?, ys)) = ...
| kinsert (y, (i, ys)) = ...
in rev (... foldl kinsert ... L)
end
否则,您将开始注意到,separate(2,0,[1,2,3,4,5])
可能会给出[1,2,0,3,4,0,5]
,而不是[1,0,2,3,0,5]