函数的输出不正确,该函数将列表的先前元素相加

时间:2019-06-03 21:14:06

标签: debugging ocaml

我正在编写应该以列表为输入并返回新列表作为输出的代码,其中对于每个索引,该索引处的值是输入列表中先前元素的总和。

这是我到目前为止所得到的:

let counter1 = ref 0;;
let rec sumthingy = fun list ->
    match list with
    | [] -> []
    | [a] -> [a]
    | hd::tl -> if List.length list > !counter1
             then (counter1:=!counter1 + 1 ;
         [ (sum list !counter1 ) ] @ sumthingy list)
         else [];;

let total = ref 0;;
let counter = ref 0;;
let rec sum = fun list n ->
    match list with
    | [] -> !total
    | [a] ->  if !counter != n then
        (counter:= !counter + 1;
        total:= !total + a; 
        !total) else !total
    | hd::tl -> if !counter != n then
        (counter:= !counter + 1;
        total:= !total + hd; 
        sum tl n) else !total;;

sum [1;2;3] 1;;
sumthingy [1;2;3];;

函数“ sum”本身可以正常工作,因此问题必须出在“ sumthingy”中。

[1; 2; 3]的预期输出为[1; 3; 6],但由于某种原因我得到了[6; 6; 6]。

注意:我知道计数器的索引不准确。 sum [1; 2; 3] 1应该输出3,但是输出1。对于我来说,这不是什么大不了的事,我只想让它工作。

2 个答案:

答案 0 :(得分:0)

考虑以下表达式:

[ (sum list !counter1 ) ] @ sumthingy list

因为您正在编写命令式代码(带有副作用),所以结果取决于@左侧和右侧的求值顺序。但是OCaml不能保证评估顺序。

我的猜测是订单不符合您的预期。

您可以使用let担保订单:

let x = expr1 in
let y = expr2 in
x @ y

这保证expr1expr2之前被评估。

(一个更好的解决方案是编写没有副作用的代码:-)

答案 1 :(得分:0)

在我看来,您正在以非常复杂的方式解决任务。这既不是惯用的,也很难阅读/调试。

我将首先采用一个简单的解决方案:

  1. 实现给定列表的函数,并且n返回从0到第n的列表元素之和

  2. 将函数从(1)馈送到map,并获得所需的结果。

类似

let sum lst n =
  let rec aux lst s m =
    match lst, m with
    | [], _ -> s
    | hd::tl, 0 -> s+hd
    | hd::tl, _ -> aux tl (s+hd) (m-1)
  in
  aux lst 0 n
;;

let sumthingy lst =
  List.mapi (fun i _ -> sum lst i) lst
;;

utop # sumthingy [1;3;5;7];;
- : int list = [1; 4; 9; 16]

这个解决方案远非最佳方案-尽管从头开始计算总和,尽管事实是,对于每个元素,我们已经计算出前一个元素的总和,所以理想情况下,我们只需要执行1个和运算就可以得到每个下一个元素。但这应该足以作为起点...