[英]Recursion in Ocaml
我是Ocaml的新手,我正在嘗試編寫一個遞歸函數。
該函數獲取一對列表並返回一對列表,例如
[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])
但是編譯器說: Error: This expression has type 'a list * 'b list but an expression was expected of type 'a list
在行中(unzip (List.tl m))
有人可以解釋為什么我有這個錯誤嗎? 而且有解決此問題的方法嗎? 非常感謝你!
let rec unzip m =
if List.length m = 0 then
([], [])
else
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
in
unzip m;;
對於任何遞歸,您都必須注意輸出類型將始終相同。
讓我們看看您的unzip
功能。
[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])
簡而言之, unzip
的返回類型是def 對(元組) ,每個元素都是一個列表,對嗎?
那我們來看一下你的代碼
let rec unzip m =
if List.length m = 0 then
([], [])
else
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
in
unzip m;;
您有兩個分支。 第一個分支正在返回([], [])
。 好吧,就返回類型而言,它是正確的,因為它是一對帶有兩個空列表並且匹配上述返回類型。
第二支
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
這是正確的嗎?
是一對有兩個元素的對,沒問題,接下來讓我們看一下第一個元素:
(fst (List.hd m)) :: (unzip (List.tl m))
您試圖將(fst (List.hd m))
到(unzip (List.tl m))
的頭部。
但是您只能使用::
將某些東西添加到列表中,因此ocaml假定(unzip (List.tl m))
是列表,對嗎?
但這是一個unzip
功能的應用程序,顯然是在一開始就描述的,您的unzip
不是返回列表,而是一對(元組)。
因此,ocaml無法理解,因此會抱怨。
以上只是為了回答有關類型問題的問題。 但是您的代碼有更多問題。
1.不正確使用的in
假設您有一個函數f1
。 您可以將其成像為母函數,這意味着它可以直接使用。 同樣在f1
,您可以聲明另一個函數或變量(或更正式地說,是綁定)。 僅當在函數內部聲明綁定時,才使用let...in...
如果僅具有母親功能,則不要in
使用,因為in where
?
在您的unzip
,您只有一個功能或綁定本身就是unzip
,並且位於頂層。 所以in
沒有必要。
2.遞歸邏輯不正確
我不知道如何在這里向您解釋遞歸,因為它需要您閱讀更多和練習更多。
但是您想法中正確的代碼是
let rec unzip = function
| [] -> ([], [])
| (x,y)::tl ->
let l1, l2 = unzip tl in
x::l1, y::l2
如果您追求的是更好的版本或尾部遞歸版本,則為:
let unzip l =
let rec unzip_aux (l1,l2) = function
| [] -> List.rev l1, List.rev l2
| (x,y)::tl -> unzip_aux (x::l1, y::l2) tl
in
unzip_aux ([],[]) l
錯誤來自以下事實: (unzip ...)
返回一對列表( 'a list * 'b list
),您在編寫(fst ..) :: (unzip ...)
。
如果您使用模式匹配,那么所有這些都將寫得更好。 骨架:
let rec unzip = function
| [] -> ...
| (x,y) :: rest ->
let (xs, ys) = unzip rest in ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.