2017-04-17 84 views
2
數組的前n個元素

我在ocaml的以下功能,總結第一c元素作爲參數傳遞的數組:遍歷OCaml中

let rec sum_array c a = 
    if c < 0 then 0 
    else a.(c) + sum_array (c - 1) a;; 

我碰巧知道什麼陣a是先進的,所以我想設置這個。我試過了:

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);; 

但OCaml抱怨模糊的'錯誤:語法錯誤',這是超級有用的。

  1. 如何解決此功能定義?我如何指定我要返回sum_array的值?
  2. 我怎樣才能讓OCaml報告更多有用的錯誤消息?

回答

5

從某種意義上說,您的問題是您在錯誤的位置添加fun c -> ...

假設您有這樣的功能:

let f count = 
    (count + 72 - 1)/72 

如果你想象的硬編碼值72是你想預先計算,你可以重寫的功能如下:

let f = 
    let line_length = 72 in 
    fun count -> (count + line_length - 1)/line_length 

您的代碼將數組放在函數的主體之前,但它應該位於內部,位於let和新的內部函數定義之間。

你的情況特別棘手,因爲你的函數是遞歸的。因此,您無法切換到fun c -> ...表單。相反,您可以在本地保留原始的基於let的定義。對於人爲的例子,它是這樣的:

let f = 
    let line_length = 72 in 
    let inner_f count = 
     (count + line_length - 1)/line_length 
    in 
    inner_f 

(作爲一個方面評論,您的代碼求和數組,而不是第一個C元件的第一C + 1種元素。)

3

誤差消息出現在;;上,因爲let沒有in只允許作爲最外面的語句。爲了使你的表達評估,你需要添加in sum_array c

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) 
    in sum_array c;; 
- : int -> int = <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) 
    in sum_array;; 

在這兩種情況下,sum_array沒有綁定在頂層。要麼你與另一個let sum_array =綁定它......,你拉的int_array綁定的定義內sum_array(如@Jeffrey斯科菲爾德提議的),或者你在頂層結合int_array定義之前sum_array

let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] 

let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1) 
;; 
0

這個答案可能看起來有點冗長,但那只是因爲我從你的錯誤中看到了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_arraysum_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]  ;; 
+0

我不知道這是爲什麼下來投了票,但謝謝你,這麼一個競爭的答案! –