2017-07-07 64 views
1

我在OCaml中爲一個學校項目實現了我自己的版本。它被定義爲這樣的:OCaml中的模式類型錯誤

type 'a my_list = 
    | Item of ('a * 'a my_list) 
    | Empty 
;; 

我的目標是實現從列表模塊20層的功能,並且第n是給了我很多的辛勤工作。它是一個遞歸函數,它也稱爲hd和長度函數。下面是代碼:

let rec length my_list = 
    match my_list with 
    | Empty -> 0 
    | Item (hd, tl) -> (length tl) + 1 
;; 

let hd my_list = function 
    | Empty -> raise (Failure "hd") 
    | Item (hd, tl) -> hd 
;; 

let rec nth my_list n = 
    let len = (length my_list) in 
    match my_list with 
    | lz when lz < 0 -> raise (Invalid_argument "nth") 
    | sup when n > len - 1 -> raise (Failure "nth") 
    | 0 -> (hd my_list) 
    | _ -> (nth my_list (n - 1)) 
;; 

在編譯時,我得到這個錯誤:

$>ocamlc -w Aelz -warn-error A mylist.ml 
File "mylist.ml", line 44, characters 10-11: 
Error: This pattern matches values of type int 
     but a pattern was expected which matches values of type 'a my_list 

參考以下行第n:| 0 -> (hd my_list)

什麼想法? 謝謝

編輯1:謝謝大家對你的wiseful答案,這裏是最後的代碼:

let rec nth my_list n = 
    if n < 0 then raise (Invalid_argument "nth") else 
    if my_list = Empty then raise (Failure "nth") else 
    if n = 0 then hd my_list else nth (tl my_list) (n-1) 
;; 

編輯2:感謝您的建議,這個人是更強類型:

let rec nth my_list n = 
    if n < 0 then raise (Invalid_argument "nth") else 
      match my_list with 
      | Empty -> raise (Failure "nth") 
      | Item (hd, tl) -> if n=0 then hd else 
        nth tl (n-1) 
;; 
+1

你不應該在'len'而不是'my_list'上匹配嗎? – Marth

+0

你是對的,謝謝! – bufferking

+2

計算列表的長度不是要走的路:長度函數需要整個列表遍歷,並且在每一次迭代中調用它!你是否曾經用一個計數器遍歷列表的單個遍歷,從0開始,並且當計數器到達N時返回元素到你所在的位置? – ghilesZ

回答

1

您正在過度使用nth函數。我不確定你寫什麼意圖,但是我正在考慮的方法:

  • 如果n是負數,則會引發錯誤。
  • 如果列表爲空,則引發錯誤。您無法獲得空列表的nth元素。
  • 如果該列表不爲空,看n是否等於0
    • 如果是的話,返回列表的頭。
    • 如果沒有,遞歸。

另外,作爲邊注,避免在基本類型的模式匹配。取而代之的

match n with 
| x when x<0 -> (* ... *) 
| _ -> (* ... *) 

喜歡使用if

if n<0 then (* ... *) else (* ... *) 

編輯

在另一方面,與非基本類型打交道時,模式匹配,強烈建議。所以,與其

if my_list = Empty then (* ... *) else (* ... *) 

喜歡以下

match my_list with 
| Empty -> (* ... *) 
| Item (hd, tl) -> (* ... *) 

而且(我認爲這是什麼導致你nth麻煩),你可以結合這兩種方法:

if n < 0 then (* ... *) 
else match my_list with 
    | Empty -> (* ... *) 
    | Item (hd, tl) -> (* ... *) 

match my_list with 
    | Empty -> (* ... *) 
    | Item (hd, tl) -> if n < 0 then (* ... *) else (* ... *) 

提示:後者可能是您所需要的nth

當然,類型檢查是在這裏,以確保你的類型是在你的代碼是一致的。

+0

我特意不給你解決方案,因爲你正在學習OCaml。但是要知道OCaml是開源的,所以如果你真的被困住了,你可以看看「真正的」List.nth函數的代碼。 ;) – RichouHunter

+0

非常感謝,非常有用的建議:) – bufferking

+0

@bufferking作爲一個練習,你也可以嘗試一個選項,要麼返回一些x或無。 – coredump