【问题标题】:Insert function using foldl/foldr使用 foldl/foldr 插入函数
【发布时间】:2018-08-16 06:06:09
【问题描述】:

我一直在研究一个单独的函数,它返回一个列表,在列表 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 来简化函数,而无需任何递归,但我似乎无法让它正常工作。关于如何解决这个问题的任何提示/建议?谢谢!

【问题讨论】:

    标签: sml ml mosml


    【解决方案1】:

    这些或多或少是我尝试使用foldl/foldr编写函数时的想法:

    • foldl/foldr 从构成最终结果的逻辑中抽象出列表递归。

    • 首先勾勒出一个与您的原始程序具有非常相似结构的函数,但其​​中使用了foldr,而kinsert 不是递归函数,而是赋予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
      

      现在折叠的结果变成了'a * 'a list,这导致了两个问题:1)我们只是想积累i暂时,但它是最终结果的一部分。这可以通过使用#2 (foldr ...) 丢弃它来规避。 2) 如果结果现在是一个元组,我不知道该放什么作为第一个 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 案例看起来与原始案例略有不同;你可能会遇到一个错误。

    • 1234563当你在第一个元素时。
    • 根据您是使用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] 而不是[1,0,2,3,0,5]

    【讨论】:

      猜你喜欢
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 2016-09-04
      • 2021-06-05
      • 2011-08-28
      相关资源
      最近更新 更多