Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ocaml noobie Q——如何使用累积参数?_Ocaml - Fatal编程技术网

Ocaml noobie Q——如何使用累积参数?

Ocaml noobie Q——如何使用累积参数?,ocaml,Ocaml,我试图通过从Euler项目学习Ocaml。我知道我想做什么,只是不知道怎么做 我有三张清单: let list1 = [1;2;3;4;5];; let list2 = [ 6;7;8;9];; let line = [9999];; 我想将数字列表2添加到列表1中的最大相邻数字,这样我就可以添加6+2、7+3、8+4和9+5来得到一个列表[8;10;12;14]。列表行[]是一个伪变量 这是我的第三次尝试: let rec meld3 l1 l2 accum = if List.len

我试图通过从Euler项目学习Ocaml。我知道我想做什么,只是不知道怎么做

我有三张清单:

let list1 = [1;2;3;4;5];;
let list2 = [ 6;7;8;9];;
let line = [9999];;
我想将数字列表2添加到列表1中的最大相邻数字,这样我就可以添加6+2、7+3、8+4和9+5来得到一个列表[8;10;12;14]。列表行[]是一个伪变量

这是我的第三次尝试:

let rec meld3 l1 l2 accum =
   if List.length l2 = 1 then
     List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
    (
     List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
     meld3 (tl l1) (tl l2) accum ;
    )
;;

let fu = meld3 list1 list2 line ;;

List.iter print_int fu;;
运行此命令后,我希望使用line=[9999;8;10;12;14],而不是line=[9999]。 OTOH,fu打印为[999914]

当我一步一步地浏览代码时,代码按照我的预期执行,但没有任何变化;else块中的累计值永远不会修改


我就是不懂这种语言。有人能提供建议吗?

好吧,我认为您还没有掌握函数式编程的本质:不是调用
List.append
并丢弃值,而是需要将该值作为参数
acum
传递给递归调用

我将通过将三角形几何与算术解耦来解决这个问题。第一个函数获取两个列表(三角形的行)并生成一个新的三元组列表,每个列表包含and元素以及该元素的左、右子元素。然后,简单映射生成一个列表,其中包含每个元素及其较大子元素的总和:

(* function to merge a list l of length N with a list l' of length N+1,
   such that each element of the merged lists consists of a triple
     (l[i], l'[i], l'[i+1])
 *)

let rec merge_rows l l' = match l, l' with
  | [], [last] -> []   (* correct end of list *)
  | x::xs, y1::y2::ys -> (x, y1, y2) :: merge_rows xs (y2::ys)
  | _ -> raise (Failure "bad length in merge_rows")

let sum_max (cur, left, right) = cur + max left right

let merge_and_sum l l' = List.map sum_max (merge_rows l l')

let list1 = [1;2;3;4;5]
let list2 = [ 6;7;8;9]

let answer = merge_and_sum list2 list1

如果您正在使用Euler 18,我建议您查找“动态规划”。

好的,让我们详细分析您的代码。这是你的原件

let rec meld3 l1 l2 accum =
   if List.length l2 = 1 then
     List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
    (
     List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
     meld3 (tl l1) (tl l2) accum ;
    )
我要做的第一件事是重写它,使Caml程序员能够理解它,而不改变任何计算。这主要意味着使用模式匹配而不是
hd
tl
。这种转变并非微不足道;简化列表操作以更容易地识别代码中的问题非常重要。如果
l2
为空,则此函数将失败,这一点也更加明显

let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [y] ->   (* here the length of l2 is exactly 1 *)
     List.append accum [ y + max x1 x2 ]
| x1::x2::xs, y::ys ->   (* here the length of l2 is at least 1 *)    
    ( List.append accum [ y + max x1 x2 ]
    ; meld3 (x2::xs) ys accum
    )
现在我认为你困难的关键是理解分号运算符。如果我写(e1;e2),语义是对e1进行副作用评估(想想
printf
),然后丢弃e1的结果。我认为您希望e1的结果变成递归调用的
acum
的新值。因此,我们没有抛弃e1,而是将其作为一个参数(这是计算实际发生变化的关键步骤):

下一步是观察我们违反了“不要重复你自己”原则,我们可以通过将
l2
中的基本情况设为空来解决这个问题:

let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [] ->   (* here the length of l2 is 0 *)
     accum 
| x1::x2::xs, y::ys ->   (* here the length of l2 is at least 1 *)    
    ( 
      meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
    )
然后我们再清理一下:

let rec meld3 l1 l2 accum = match l1, l2 with
| _, [] -> accum 
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
最后,对
append
的重复调用使代码具有二次性。这是一个累积参数的经典问题,有一个经典解决方案:按相反顺序累积答案列表:

let rec meld3 l1 l2 accum' = match l1, l2 with
| _, [] -> List.rev accum' 
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (y + max x1 x2 :: accum')
我已将名称
acum
更改为
acum'
;素数是按相反顺序排列的列表的常规值。最后一个版本是我编译的唯一版本,我没有测试任何代码。(我在另一个答案中测试了代码)


我希望这个答案更有帮助。

(什么?我只能用300个字符或更少的字符回答?!)我还没有掌握函数式编程的基本原理;这就是我这么做的原因之一。你能解释一下为什么'List.append acum[x]'不将x附加到acum吗?我相信你的方式很好;我想知道为什么我的不起作用。简短的版本是它做了追加,但是分号操作符把结果扔掉了。我将发布更长的答案。List.append accum[x]返回一个新列表,而不是修改accum。非常有用,谢谢。我不知道这件事-语义学。我之前尝试过匹配,但只有简单化的例子可供参考。我知道其他问题(重复我自己,等等);一旦我弄明白发生了什么事,我就会抽出时间来修理它们。:-)这是一个古老的问题,但我对任何研究上述问题的人的建议是,将三角形表示为整数数组。在Ocaml中,数组是可变的,因此很容易记住每个级别的小计。。。
let rec meld3 l1 l2 accum' = match l1, l2 with
| _, [] -> List.rev accum' 
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (y + max x1 x2 :: accum')