递归调用结束函数的Ocaml问题



我正在尝试调用代码中的最后一个函数,直到得到最后两个列表的总和。

我试图解决的问题是:

有x个cookie和n个子项。返回给的Cookie列表列表中的每个孩子,如果您给每个孩子n+1个cookie迭代。如果在这一点上,你的cookie比你应该提供的要少,把剩下的交给最后一个孩子,然后停下来。

这是我的代码:

let rec spread a b c = 
if a = [] then spread (List.tl a) (b-c) (c+1)
else if List.tl a = [] then [List.hd a+c]
else if c > b-c then List.hd a + c :: [(List.hd (List.tl a))+b-c]
else 
(List.hd a + c) :: spread (List.tl a) (b-c) (c+1) 

此功能的工作方式如下:

排列(范围3(11 1->call
int list=[1;2;3]->输出

扩散(范围3(5.4->call
int list=[4;1]->输出

(范围3(调用给出具有3个零的列表->[0,0,0]

现在我制作了list_sum函数,用于汇总列表:

let rec sum_list2 x y = 
if x = [] then y
else if y = [] then x 
else 
List.hd x+List.hd y :: sum_list2 (List.tl x) (List.tl y) 

最后,我必须制作一些可以这样调用的函数:

x(cookie数量(n(子项数量(

函数n x=。。。

我做了这个,但它只加在第一和第二个列表的总和上。我需要对所有列表求和,直到没有cookie为止,所以它应该重新调用spread直到结束,并对spread中的所有列表求总和。

let rec f5 x n =
if n = 1 then [x] 
else
let brojac = 0 in
let y = dijeli (range n) x 1 in
if (sum(y) < x) then
sum_list y (f5 (x - sum(y)) (brojac+n))
else y

https://gist.githubusercontent.com/hxra/2d5bd66b92b53c135b8ee255500c873f/raw/abff79ae3431a224a07a373551a2e09c19f874d4/cookies%2520and%2520children

链接到可以在ocaml在线编辑器中测试的完整代码。

您有一种非常令人困惑的命名变量和函数的方法,这会让您大吃一惊。试着重写你的代码,选择更好的名字,我敢打赌你会立即发现问题所在。

例如,在递归内部的函数f5中,您总是用1而不是brojac调用dijeli,此外,brojac变量永远不会改变,并且总是等于零,因此brojac+n总是等于n,因此在每次迭代中,您都会将n增加0

您还混淆了变量n,您有时将其用作子代的数量,例如(range n),有时还将其用作将苹果传递给子代的轮数。显然,在递归函数中需要一个额外的变量。

总之,我的建议如下:

  1. 使用所有变量的一致名称重写所有内容,不包括abcf5。记住,编程首先是关于理解。你对问题的理解,所以你的问题应该是可读的。

  2. 识别你的归纳变量——在递归的每一步中都会发生变化的变量。

  3. 缩进循环不变量,即循环必须为true才能继续的条件。

好消息是,你已经非常接近工作解决方案了,只是糟糕的命名给你带来了太多的认知负担,以至于你无法通过最后一步。所以休息一下,选择合适的名字,一切都会好起来的。

第页。以突出显示您出错的确切位置:

  1. let brojac = 0 in不,它不应该为零
  2. dijeli (range n) x 1不,你传递的不是一个苹果,而是本轮拆分的苹果数量
  3. f5 (x - sum(y)) (brojac+n),不是brojac+n,而是整数,您甚至没有变量

如果我理解规范

(* Immersion for target function *)
(* Non tail recursion *)
let rec spread_G cookies slot children = 
if children==1 then [min cookies slot] 
else if cookies < slot then 0 ::spread_G cookies slot (children - 1)  
else slot :: spread_G (cookies - slot) slot (children - 1) ;;
(* P : children > 0 , cookies >= 0 *)
(* Target  function, Initial call *)
let spread cookies children = spread_G cookies (children + 1) children ;;

spread 20 4 ;; (* 20 cookies for 4 boys, each one ideally 4+1 = 5 . [5;5;5;5] *)
spread 16 4 ;; (* 16 cookies. Not enough for all  [5;5;5;1] *)
spread 12 4 ;; (* 10 cookies. Not enough even for last but one.[5;5;0;2] *)               

我必须强调,这个问题至少对一个孩子来说是有意义的。我也可以做一个尾部递归,但会是";更硬";阅读。

最新更新