使用累计总和创建新列表

时间:2013-09-09 04:30:42

标签: ocaml

我正在努力解决这个问题

  

练习8.3编写一个带有数字和返回列表的函数   累计金额;也就是说,一个新的列表,其中第i个元素是   原始列表中第一个i + 1个元素的总和。例如,   累积和[1,2,3]为[1,3,6]。

我写了这段代码,根据我的说法是正确的。

let lastItem = function 
  | [] -> 0
  | l -> List.hd (List.rev l);;

let rec cumulativeSumActual accum input =
match input with
  | [] -> accum
  | hd::tl -> cumulativeSumActual (accum::[(lastItem accum) + hd]) tl;;

let cumulativeSum = cumulativeSumActual [];;

let output = cumulativeSum [1; 2; 3;];;

let printer item =
    print_int item
    print_string "\n";;

List.iter printer output

但是我收到了错误

user1@ubuntu:~/Documents/Programs$ ocamlc -o CumulativeList CumulativeList.ml
File "CumulativeList.ml", line 8, characters 33-38:
Error: This expression has type 'a list
       but an expression was expected of type 'a

然后我将代码更改为

  | hd::tl -> cumulativeSumActual (accum@[(lastItem accum) + hd]) tl;;

它有效!

但是我不明白为什么cons运算符不起作用,为什么新列表会附加运算?

cons运算符应该只是在列表中添加一个新项目,然后将新列表作为递归调用的第一个参数返回?

发生了什么事?

2 个答案:

答案 0 :(得分:1)

你有这个表达:

lastItem accum

lastItem的参数类型为'a list

因此,accum的类型为'a list

运算符::左侧需要一个元素,右侧需要一个列表,但是您将其应用到左侧的列表中,因此出现错误。 @运算符允许在任何一方使用列表,因此它运行正常。

答案 1 :(得分:1)

首先,con是将元素推送到头部的列表。例如,12::[13,1,3]。您不能con (::)列表中的列表。在您的代码中,accum显然是'a list,而不是'a。您的代码(accum :: [(lastItem accum)+ hd])正在尝试con两个列表,对吗?

其次,@是连接两个列表的append,这就是为什么你的 | hd :: tl - > cumulativeSumActual(accum @ [(lastItem accum)+ hd])tl ;; 是正确的。

第三,我建议解决方案是

let c_sum l =
  let rec sum pre acc = function
    | [] -> acc
    | hd::tl -> let tmp_sum = pre+hd in sum tmp_sum (tmp_sum::acc) tl
  in sum 0 [] l

P.S。,当您尝试连接两个列表时必须小心,因为通常此操作将采用O(n),因为它需要遍历一个列表。