这个答案可能看起来有点冗长,但那只是因为我从你的错误中看到了OCaml的一些基本概念中的某些缺乏理解。这可能是一个很好的机会来澄清一些事情。
范围和顺序OCaml中
您可能会或可能不会已经已经明白这个话题。由于它们是接下来的基础,我仍然不得不详细说明这一点。
想想你将如何测试代码:
let rec sum_array c a =
if c < 0 then 0
else a.(c) + sum_array (c - 1) a
in
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |] ;;
我假定你所熟悉的普通的编程语言。把它放在一个Java方法:
//Java version
int a = 1;
int b = 1;
int c = a + b;
将被翻译成的OCaml的代码:
(* OCaml version *)
let a = 1 in
let b = 1 in
let c = a + b in
c ;;
他们是不是所有的不同。乍一看,OCaml代表测序的方式(即;
)似乎很乏味。但随着你的函数式编程之旅的继续,你会更加了解这种机制的重要性。
错误的逻辑
至于结果表明:
let rec sum_array c a =
if c < 0 then 0
else a.(c) + sum_array (c - 1) a
in
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |] ;;
(* - : int = 6 *)
你在这里做的逻辑是一个小故障。你的功能增加了一个以上的元素。修复很简单:
let rec sum_array c a =
if c = 0 then 0
else a.(c - 1) + sum_array (c - 1) a
in
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |] ;;
(* - : int = 3 *)
它的工作现在。该函数现在总结数组的第一个元素。
如何存储[| 1; 2; 3; 4; 5 |]添加到函数中,这样只需要参数n
?
我想这就是你所说的意思:我碰巧预先知道阵列a。
这里是简单的代码来做到这一点非常小的变化:
sum_array 3;;
(* - : int = 6 *)
看到这里的变化不大,只是用另一种let ... in
:
let rec sum_array c =
let a = [| 1 ; 2 ; 3 ; 4 ; 5 |] in
if c = 0 then 0
else a.(c - 1) + sum_array (c - 1) ;;
然后你就可以像这样运行它在函数定义中硬编码a
的定义。这正是如何在java中做同样的事情。
有人说,你自己的代码有什么问题?
您的代码:
fun c -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in
let rec sum_array c =
if c < 0 then 0
else int_array.(c) + sum_array (c - 1);;
失败的原因有两个:
- 如影随形:它看起来像,该函数只有
c
作为参数,但实际上它是通过后不做任何处理c
在。这是因为您的函数sum_array
(这是外部整体函数的辅助函数)有另一个相同的名称参数c
,并且此参数会影响绑定或最外面的参数c
的定义。
- 范围:在这个大功能的定义范围内,您定义了
int_array
和sum_array
。但它们都是本地名称,并且您没有返回任何内容。回想一下,函数的返回值是整个表达式在箭头右侧的值。这种情况下的价值是什么?除了一些局部变量的定义之外,什么都没有,只要函数结束就会过期。
这是正确的代码:
fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in
let rec sum_array c =
if c < 0 then 0
else int_array.(c) + sum_array (c - 1)
in sum_array arg
但还有另一个问题,上述这种功能,是一款功能。这意味着这是一个价值。如果你现在没有将一个值绑定到一个变量上,你现在就使用它,或者你失去了它的踪迹。因此,这里要做的更好的事情是:
let sum_first_n =
fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in
let rec sum_array c =
if c < 0 then 0
else int_array.(c) + sum_array (c - 1)
in sum_array arg ;;
现在,您可以像调用其他函数一样调用它。
当然,我仍然在这段代码中使用错误的逻辑。解决这个问题,我们有:
let sum_first_n =
fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in
let rec sum_array c =
if c = 1 then int_array.(0)
else int_array.(c - 1) + sum_array (c - 1)
in sum_array arg ;;
sum_first_n 3;;
(* - : int = 6 *)
现在一切正常。
如何做到更多功能?
如果给出List的参数而不是数组,那该怎么办?你如何做到没有突变?
这是一种很好的做法,可以帮助您更快地掌握OCaml。
下面是代码:
let rec sum_array c l = match c,l with
| _, [] | 0, _ -> 0
| (_, hd::tl) -> hd + sum_array (c-1) tl
in sum_array 4 [1;2;3;4;5;6] ;;
我不知道这是为什么下来投了票,但谢谢你,这么一个竞争的答案! –