Sml 使用foldl/foldr插入函数

Sml 使用foldl/foldr插入函数,sml,ml,mosml,Sml,Ml,Mosml,我一直在研究一个单独的函数,该函数返回一个列表,在列表l的每个k个元素之后插入元素x(从 列表的末尾)。例如,separate(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)

我一直在研究一个单独的函数,该函数返回一个列表,在列表l的每个k个元素之后插入元素x(从 列表的末尾)。例如,separate(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简化函数,而不使用任何递归,但我似乎无法使它正常工作。关于如何实现这一点,有什么提示/建议吗?谢谢大家!

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

fun separate (k, x, L) =
    let fun kinsert (y, ys) = ...
    in foldr kinsert [] L
    end
  • 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
    
    现在折叠的结果变成了一个列表,这导致了两个问题: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
    
  • <> L> >P>你原来的代码> KySert < /C>偏离了一个折叠方式的递归模式:在中间模式中,当<代码> 匹配<代码> 0 > /代码>时,你并没有砍掉一个元素“<代码> ls <代码> >,否则折叠会迫使你。因此,您的
    0
    案例看起来与原始案例略有不同;你可能会遇到一个错误

  • 请记住,
    foldr
    实际上首先访问列表中的最后一个元素,此时
    i
    将具有其初始值,其中对于原始
    kinsert
    i
    的初始值将在您位于第一个元素时

  • 根据您使用的是
    foldl
    还是
    foldr
    ,您将遇到不同的问题:
    foldl
    将反转列表,但按正确的顺序处理项目
    foldr
    将保持列表顺序正确,但当
    k
    不划分
    L
    的长度时,将创建不同的结果

  • >P>,考虑使用<代码> 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]