我一直在研究一个单独的函数,它返回一个列表,在列表l的每个k元素之后插入元素x(从中计算) 列表的结尾)。例如,单独的(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)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
我现在尝试使用foldl / foldr简化函数而不进行任何递归,但我似乎无法使其正常工作。有关如何处理此问题的任何提示/建议?谢谢!
答案 0 :(得分:1)
这些或多或少是我尝试使用foldl
/ foldr
编写函数时的想法:
foldl
/ foldr
从构成最终结果的逻辑中抽象出列表递归。
首先绘制一个与原始程序结构非常相似的函数,但使用foldr
而kinsert
而不是递归函数的函数是给{的函数{1}}:
foldr
这不是必须的; fun separate (k, x, L) =
let fun kinsert (y, ys) = ...
in foldr kinsert [] L
end
也可能是匿名的。
您正在使用内部帮助函数kinsert
,因为您需要kinsert
(k
)的副本,然后逐渐递减并重置为i
每当它达到0时,k
吐出的列表相当于折叠的累积变量,kinsert
暂时累积(偶尔重置) )以同样的方式。
更改i
的累积变量,为kinsert
腾出空间:
i
现在折叠的结果变为fun separate (k, x, L) =
let fun kinsert (y, (i, xs)) = ...
in foldr kinsert (?, []) L
end
,这会导致两个问题:1)我们只想暂时累积'a * 'a list
,但它的一部分最后的结果。这可以通过使用i
丢弃它来规避。 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
偏离折叠以一种方式执行的递归模式:在中间模式中,当kinsert
与i
匹配时,您不是从0
切掉一个元素,否则会折叠你的元素。因此,ls
案例与原始案例略有不同;你可能会遇到一个错误的错误。
请记住,0
实际上会先访问列表中的最后一个元素,此时foldr
将具有其初始值,其中原始i
为初始值当你在第一个元素时,kinsert
就会出现。
根据您使用i
还是foldl
,您会遇到不同的问题:foldr
会反转您的列表,但会按正确的顺序处理项目。 foldl
会保持列表顺序正确,但在foldr
未划分k
的长度时会创建不同的结果...
此时,请考虑使用L
并反转列表:
foldl
否则,您会开始注意到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]
。