我需要在ML中实现一个powerset函数,该函数采用具有以下约束的整数列表:
1)除了map,foldr和foldl之外,不要调用内置的库函数 2)永远不要递归。所有递归都发生在地图和折叠中 3)永远不要包含let或local表达式
我已经使用表单的正常递归实现了没有这些约束的函数:
Powerset(x :: xs)= powerset(xs)@ x.powerset(xs)
我很难想到将这种类型的实现转换为仅使用地图和折叠的方法。
我不一定要求有人为我实施,但我会感谢你在正确的方向上轻推或者提供任何帮助。
Thakns
答案 0 :(得分:2)
以下是我如何解决折叠问题。
考虑您想要获得的最终价值。在您的情况下,这将是输入列表的powerset。现在关键的问题是:在插入新元素后,可以重新计算列表的powerset吗?也就是说,给定P(S)
,某些项目S
的幂集,可以仅P(S ∪ {x})
和P(S)
来计算x
?< / p>
我相信你已经明确回答了这个问题。也许没有明确说明,但是如果你重写了Powerset
函数,你会发现正确的想法隐藏在其中。您将要将此代码打包成一个小帮助函数:
fun extendPowerset (PS : 'a list list, x : 'a) : 'a list list =
(* PS is the powerset of some set S. This function
* should return the powerset of S ∪ {x}. *)
...
太好了,现在你怎么把它插入折叠?好吧,在折叠的每一步,你都会得到两件事:
作为回报,您必须计算稍大的摘要:除了之前的所有内容,它还应总结下一个元素。这种感觉有点模糊吗? extendPowerset
函数基本上完全符合您的需要,其中&#34;摘要&#34;以前的元素是这些元素的动力。我会把剩下的留给你。
除此之外:请注意,您还可以使用折叠附加两个列表。作为提示,尝试计算foldl op:: [1,2] [3,4]
计算的值。它不太像追加[1,2]
和[3,4]
,但它已接近......
答案 1 :(得分:2)
就像你已经完成的那样,我也会首先使用显式递归编写一个powerset函数。然后我会尝试发现高阶函数模式,然后用一个模式一次替换它们。
例如,你可以转一个辅助函数
fun consMany (x, []) = []
| consMany (x, L::Ls) = (x::L) :: consMany (x, Ls)
进入表达式
map (fn L => x::L) Ls
您可以删除let-expression(对于重复使用一次计算的值两次非常有用)
fun foo (x::xs) =
let val rest = foo xs
in ... x ... rest ... rest ...
end
使用函数:
fun foo (x::xs) =
bar (x, foo xs)
and bar (x, rest) = ... x ... rest ... rest ...
尽管如此,这可能也是一个匿名函数:
fun foo (x::xs) =
(fn rest => ... x ... rest ... rest ...) (foo xs)
您可能会转换列表递归函数
fun derp [] = ...
| derp (x::xs) = g (x, derp xs)
进入折叠:
fun derp xs = foldr g (...) xs
但如果结果的顺序无关紧要,foldl
is tail-recursive。