【问题标题】:SMLNJ powerset functionSMLNJ powerset 函数
【发布时间】:2018-02-04 06:52:40
【问题描述】:

我正在尝试打印从以下幂集函数创建的列表的大小

fun add x ys = x :: ys;
   fun powerset ([])  = [[]]
   | powerset (x::xr) = powerset xr @ map (add x) (powerset xr) ;

val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list;

我有列表大小功能

fun size xs = (foldr op+ 0 o map (fn x => 1)) xs;

我无法合并这两个函数并得到类似的结果

我需要这样的东西:

[(0,[]),(1,[3]),(1,[2]),(2,[2,3]),(1,[1]),(2,[1,3]),(2,[1,2]),(3,[1,2,3])]

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 您对powerset 的定义毫无意义。在一个子句中,您使用了名称powerset,然后在下一行中,您似乎改变了主意并想将其命名为subsets1。它是哪一个?您是要定义一个名为powerset 的函数还是要定义subsets1?如果subsets1 已经被定义——它的代码是什么?
  • 感谢 John 注意到它,它是一个 poweset 函数而不是子集 1

标签: functional-programming sml smlnj ml powerset


【解决方案1】:

您可以使用内置的List.length 获取列表的长度。

您似乎忘记提及您只能使用高阶函数的限制。 (我猜你有这个约束,因为现在其他人都在问如何用这个约束编写 powerset 函数,并且像你一样使用foldr 来计数,似乎有点构建。)

您的示例表明您正在尝试计算列表列表中的每个列表,而不仅仅是一个列表的长度。为此,您需要在列表列表中映射计数函数。但这只会给你一个长度列表,而你想要的输出似乎是一个包含长度和实际列表的元组列表。

这里有一些提示:

  1. 你也可以use foldl rather than foldr,因为加法是关联的。

  2. 您不需要先map (fn x => 1) - 这会增加不必要的列表迭代。你这样做可能是因为折叠看起来很复杂,而你只是设法写了foldr op+ 0。这是没有理解 fold 的第一个参数的症状。

    尝试使用匿名函数而不是 op+ 来编写折叠表达式:

    fun size L = foldl (fn (x, acc) => ...) 0 L
    

    将此与op+ 进行比较,如果将其写成匿名函数,则如下所示:

    fn (x, y) => x + y
    

    使用op+ 折叠带有 + 运算符的一些非常隐含的用法:您想丢弃一个操作数(因为不是它的值而是它的存在很重要)并将另一个操作数用作累积变量(通过调用更好地理解这一点它是acc 而不是y)。

    如果您不确定我所说的累积变量是什么意思,请考虑size 的递归版本:

    fun size L =
        let fun sizeHelper ([], acc) = acc
              | sizeHelper (x::xs, acc) = sizeHelper (xs, 1+acc)
        in sizeHelper (L, 0) end
    

    它的辅助函数有一个额外的参数,用于通过递归调用携带结果。这使得函数尾递归,折叠是这种技术的一种推广; fold 的辅助函数的第二个参数(作为参数给出)是累加变量。 (fold 的辅助函数的第一个参数是单个参数而不是列表,这与上面 size 的显式递归版本不同。)

  3. 鉴于您的size 函数(又名List.length),您只完成了三分之一,因为

    size [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
    

    给你 8 而不是 [(0,[]),(1,[3]),(1,[2]),(2,[2,3]),...)]

    所以你需要编写另一个函数,(a)size 应用于每个元素,这将给你[0,1,1,2,...],并且 (b) 以某种方式组合输入列表[[],[3],[2],[2,3],...]。您可以使用zip/map 分两步执行此操作,也可以仅使用foldr 分步执行。

    尝试将一个什么都不做foldr表达式写入输入列表L

    foldr (fn (x, acc) => ...) [] L
    

    (与op+ 一样,使用op:: 而不是编写匿名函数会作弊。)

    然后将每个x 视为一个列表。

【讨论】:

  • 感谢您的帮助,但我不应该使用 List.length 等内置函数
  • 您是否准确且仅阅读了此答案的第一行? :-)
猜你喜欢
  • 1970-01-01
  • 2020-05-01
  • 2022-01-24
  • 1970-01-01
  • 2018-07-12
  • 1970-01-01
  • 2010-10-14
  • 2019-03-09
  • 2015-05-29
相关资源
最近更新 更多