int列表的累计和

时间:2019-03-17 13:56:00

标签: recursion functional-programming sml smlnj

我实现了以下求和函数:

fun cumsum_reverse (xs: int list) = 
  if null xs then [0]
  else
    let val tl_cumsum = cumsum_reverse (tl xs)
    in
      hd xs + hd tl_cumsum :: tl_cumsum
    end

fun reverse (first: int list, second: int list) =
  if null first
  then
    second
  else
    reverse (tl first, hd first :: second)

fun cumsum (xs: int list) = 
  tl(reverse(cumsum_reverse(reverse(xs, [])), []))

测试用例:

val test = cumsum[1,4,20] = [1,5,25]

有什么方法只能使用一个功能来实现吗?

2 个答案:

答案 0 :(得分:2)

我将根据通用scanl函数对此进行定义。它类似于foldl,但会产生一个中间结果列表。它的工作原理与累积总和非常相似,但是使用了+运算符和参数化的默认元素。它在标准库中不可用,但也可能已经存在。

fun scanl _ _ [] = []
  | scanl f y0 (x::xs) =
    let val y1 = f (x, y0)
    in y1 :: scanl f y1 xs
    end

然后:

val cumsum = scanl op+ 0
  

有什么方法只能使用一个功能来实现吗?

这取决于您所说的“仅一个功能”。

只有一个功能吗? cumsum仅将一个列表作为输入,并且您需要一个额外的参数来跟踪累积的总和。由于累加结果的函数不能直接为cumsum,因此需要两个函数。那么,您的意思是“ cumsum之外的一个命名函数”吗?然后scanl或matt的内部帮助函数将解决此问题。

如果您只能使用标准库函数定义cumsum

val cumsum = tl o rev o foldl (fn (x, y::ys) => x + y :: y :: ys) [0]

然后cumsum成为您声明的唯一函数。

如果您只能使用单个标准库函数定义cumsum,那么我会使用foldl

val cumsum = (fn (_::xs) => xs)  (* tl *)
           o foldl op:: []       (* rev *)
           o foldl (fn (x, y::ys) => x + y :: y :: ys) [0]

然后cumsum成为您声明的唯一函数,并且只使用了一个名为standard-library的函数即可。 (如果它不是标准库函数,则必须先声明它,然后再声明两个函数。)

但这变得有点傻了。 :-)

答案 1 :(得分:1)

当然,这是我仍然使用多种功能的一种方法, 但是它只是保持累加和并从0开始递归的助手。

但是,递归循环完全发生在helper函数中,该函数的名称相同,目的是故意遮盖第一个。

fun cumsum (xs : int list) =
  let fun cumsum (x::xs, sum) = let val foo = x + sum in foo::cumsum(xs, foo) end
        | cumsum ([], _) = []
  in cumsum (xs, 0) end