[英]Recursion using OCaml and unzip
我進行了模式匹配,並且工作正常:
let rec unzip l =
match l with
|[] -> ([], [])
|(x,y)::tail ->
let (first, second) = unzip tail in
(x::first, y::second)
但是我該如何使用地圖或向右折疊(僅提示,請勿告訴我如何實際操作)
我在考慮以下方面:
let unzip : ('a * 'b) list -> 'a list * 'b list = let (first,second) = map (fun (x,y) -> (x::first, y::second) );;
但是出現語法錯誤
如果您查看List.map
的類型:
# List.map;;
- : ('a -> 'b) -> 'a list -> 'b list = <fun>
您會看到它總是返回一個列表。 由於要返回一對列表,因此不能使用List.map
。 您可以使用折疊。 或者,您可以List.map
對中的每個列表調用一次List.map
。
更新
讓我們使用List.fold_left
,我認為這要容易一些。
fold_left
的本質是找出一個執行計算步驟的函數。 該函數將到目前為止累積的答案以及該列表的一個新元素取走。 返回值是新的累積答案。 如果可以定義這樣的功能,則可以將其折疊在輸入列表上以獲得完整的答案。
一種看待這種情況的方法是,您的函數正是作為for
語句主體出現的函數。 for
的主體也執行一個計算步驟。
假設我要添加一個整數列表。 因此,我想要的函數將到目前為止的累積答案(一個int),列表中的下一個值(一個int)作為新值,並返回新的累積答案(兩個int之和)。 因此,要折疊的函數如下所示:
let foldme a b = a + b
如果將其折疊為一個整數列表,您將得到總和:
# let foldme a b = a + b;;
val foldme : int -> int -> int = <fun>
# List.fold_left foldme 0 [3; 5; 7; 11];;
- : int = 26
如果要反轉列表,則需要一個函數,該函數可將答案(到目前為止為列表的第一部分)與列表的新元素相乘,然后返回帶有在開頭添加的新值的反轉。 因此,您想要的功能如下所示:
let foldme2 a b = b :: a
如果將其折疊在列表上,則會得到列表的反面:
# let foldme2 a b = b :: a;;
val foldme2 : 'a list -> 'a -> 'a list = <fun>
# List.fold_left foldme2 [] [4; 5; 6; 7];;
- : int list = [7; 6; 5; 4]
如果您可以找出執行一步計算的函數,則可以找出如何進行折疊。 確實需要一段時間才能做到。
let f (l,s) (x,y) = (x::l,y::s);;
let unzip l = List.fold_left f ([],[]) (List.rev l);;
您可以使用List.map
兩次:一次fst
並曾經與snd
。 但是,我建議您花些時間了解List.fold_right
和List.fold_left
因為它們在許多情況下都很有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.