[英]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.