仅使用map和folds在ML中实现powerset函数

时间:2018-02-01 21:03:14

标签: recursion sml fold ml powerset

我需要在ML中实现一个powerset函数,该函数采用具有以下约束的整数列表:

1)除了map,foldr和foldl之外,不要调用内置的库函数 2)永远不要递归。所有递归都发生在地图和折叠中 3)永远不要包含let或local表达式

我已经使用表单的正常递归实现了没有这些约束的函数:

Powerset(x :: xs)= powerset(xs)@ x.powerset(xs)

我很难想到将这种类型的实现转换为仅使用地图和折叠的方法。

我不一定要求有人为我实施,但我会感谢你在正确的方向上轻推或者提供任何帮助。

Thakns

2 个答案:

答案 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}. *)
  ...

太好了,现在你怎么把它插入折叠?好吧,在折叠的每一步,你都会得到两件事:

  1. 列表的下一个元素,
  2. 从所有先前元素计算的某些值(将其视为&#34;摘要&#34;之前的元素)
  3. 作为回报,您必须计算稍大的摘要:除了之前的所有内容,它还应总结下一个元素。这种感觉有点模糊吗? 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