gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 16:50:14 25 4
gpt4 key购买 nike

我正在尝试通过研究 Problem 18 来学习 Ocaml来自欧拉计划。我知道我想做什么,只是不知道该怎么做。

我有三个列表:

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

我想将数字 list2 添加到 list1 中的最大相邻数字,IOW 我将添加 6+2、7+3、8+4 和 9+5 以获得列表 [8;10;12;14]。列表 line[] 是一个虚拟变量。

这是我的第三次尝试:
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 block 中的累加器永远不会被修改。

我就是不懂这种语言。任何人都可以建议吗?

最佳答案

好的,让我们分解你的代码。这是你的原件。

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 程序员能够理解它,而无需更改任何计算。这主要意味着使用模式匹配而不是 hdtl .这种转变不是微不足道的。简化列表操作以更容易识别代码问题非常重要。如果 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 的结果成为 accum 的新值用于递归调用。因此,我们没有丢弃 e1,而是将其设为参数( 这是计算实际发生变化的关键步骤 ):
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 *)
(
meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
)

下一步是观察我们是否违反了不要重复自己的原则,我们可以通过设置 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')

我已更改名称 accumaccum' ;对于以相反顺序排列的列表,素数是常规的。最后一个版本是我编译的唯一版本,我还没有测试任何代码。 (我确实在我的另一个答案中测试了代码)。

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

关于Ocaml noobie Q——如何使用累加参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/524616/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com