如何在OCaml中无递归实现更简洁的map函数?
用非递归方式实现OCaml的List.map函数
我已经用递归实现了OCaml的List.map,现在想找一种无需递归的更简洁实现方式。目前已经通过List.fold_left结合Fun.flip实现了reverse函数,代码如下:
(* given *) type 'a list = | [] | (::) of 'a * 'a list let nil : 'a list = [] let cons (hd : 'a) (tl : 'a list): 'a list = hd :: tl let reverse (ls : 'a list): 'a list = List.fold_left (Fun.flip cons) [] ls
我考虑用@@(应用操作符)、%(函数组合操作符)、Fun.flip或List.fold_left来实现,但尝试下面的代码时出现了错误,想请求相关提示:
List.fold_left (fun x -> f x) [] ls
问题分析与实现提示
你写的这段代码有两个核心问题:
- fold_left的参数顺序错误:
List.fold_left的累加器函数参数顺序是(累加器 -> 元素 -> 累加器),而你写的fun x -> f x只处理了元素,没有结合累加器构建新的列表。 - 直接用f处理元素无法构建列表:
f x只是把单个元素映射后的结果返回,没有用cons把它添加到累加器里。
正确的思路是结合fold_left和cons,但因为fold_left是从左到右遍历,直接用cons会得到反转后的映射列表,所以最后需要套一层reverse来修正顺序。
正确实现方式
方式一:结合fold_left、Fun.flip和reverse
let map (f : 'a -> 'b) (ls : 'a list) : 'b list = reverse (List.fold_left (fun acc x -> cons (f x) acc) [] ls)
用函数组合简化写法:
let map f = reverse % List.fold_left (fun acc x -> cons (f x) acc) []
方式二:用Fun.flip简化累加器函数
cons的参数是(元素, 列表),而fold_left需要的累加器函数是(列表, 元素) -> 列表,可以用Fun.flip cons配合映射后的元素:
let map f = reverse % List.fold_left (Fun.flip (cons % f)) []
这里cons % f先把元素用f映射,再传给cons,然后用Fun.flip调整参数顺序适配fold_left的要求。
方式三:用fold_right(可选)
如果允许使用List.fold_right,实现会更直观——它从右到左遍历,不需要反转:
let map f ls = List.fold_right (fun x acc -> cons (f x) acc) ls []
内容的提问来源于stack exchange,提问作者Emptieeee1021
相关产品推荐
相关产品推荐

