這個答案可能看起來有點冗長,但那只是因爲我從你的錯誤中看到了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] ;;
我不知道這是爲什麼下來投了票,但謝謝你,這麼一個競爭的答案! –