我尝试将 1 添加到 Ocaml 列表中的每个元素有什么问题?

What's wrong with my attempt to add 1 to every element in my list in Ocaml?

我不明白我收到的错误消息或我正在尝试做的事情有什么问题

我只想使用 List.fold_left 将我的 add1 函数应用于此列表 [1,2,3]

我的 add1 函数应该只为每个元素加 1,所以我会得到 [2, 3, 4]

我做这个练习的主要目的只是为了试验 List.fold_left。我其实并不关心加1,我只是选择那个函数,因为它看起来很容易写(我是一个ocaml初学者)。

我的最终目标实际上是使用 List.fold_left 和其他地方已经编写的函数来填充空 StringMap 的键,因此如果有人对此有深入了解,也将不胜感激

这是第一次尝试(我试了两次)

let rec add1 = function
  | [] -> []
  | h::t -> (h+1)::(add1 t) in List.fold_left add1 [1, 2, 3];;

这是第二次尝试

 let a(b) =
let rec add1 = function
  | [] -> []
  | h::t -> (h+1)::(add1 t)
in 
let c = List.fold_left add1 b
in a [1,2,3];;

我认为你应该从:

开始
let add x = x + 1

然后构建一个函数,通过 List.fold_left:

将函数应用于列表
let apply_f_to_list_elements fn lst = (*use List.fold_left here*)

您确定要 List.fold_left 而不是 List.map 吗?

您似乎混淆了 mapfold_left 我认为这句话可以帮助您理解其中的区别:

Imagine you have a big dinner with numerous people. You are serving the dish: you go through all the people and replace their empty plates with plates containing food. This is a map operation: the number of plate on the table didn't change, but for each plate, you have done the same action (changing the content of the plate). Once everything is done, you collect all the dirty plates: This is a fold operation, at the end, there are no more plates on the table, but you have done something for each plates (stacking them) and return the file result (a stack of dirty plates). In both case, an action is applied systmatically. The difference is that Map preserves the current "structure" (the plates on the table) while Fold removes the structure, and build something else."

它可能会帮助您了解如何实施 fold_left

let rec fold_left f init lst =
  match lst with
  | [] -> init
  | x::xs -> fold_left f (f init x) xs

所以考虑一下当像求和函数这样的东西起作用时,当按照 fold_left 实施时会发生什么。

let sum lst = 
  fold_left (+) 0 lst

如果我们评估sum [1; 2; 3; 4]

sum [1; 2; 3; 4]
fold_left (+) 0 [1; 2; 3; 4]
fold_left (+) (0 + 1) [2; 3; 4]
fold_left (+) (1 + 2) [3; 4]
fold_left (+) (3 + 3) [4]
fold_left (+) (6 + 4) []
10

我们可以根据 fold_left:

来定义 map
let map f lst =
  let f' init x = f x :: init in
  fold_left f' [] lst

让我们评估一下map (fun x -> x + 1) [5; 2; 6]

map (fun x -> x + 1) [5; 2; 6]
fold_left f' [] [5; 2; 6]
fold_left f' (5 + 1 :: []) [2; 6]
fold_left f' (2 + 1 :: [6]) [6]
fold_left f' (6 + 1 :: [3; 6]) []
[7; 3; 6]

现在,由于我们解构和创建列表的方式,结果是倒退的。我们可以用 fold_left 通过反转结果列表来克服这个问题。

let map f lst =
  let f' init x = f x :: init in
  let lst' = fold_left f' [] lst in
  List.rev lst'

或使用 |> 运算符:

let map f lst =
  let f' init x = f x :: init in
  fold_left f' [] lst |> List.rev

更上一层楼

在每次迭代中,fold_left 将列表中的第一个元素和累加器转换为下一次迭代的累加器。如果您想将这个概念应用到您的 StringMap 模块,请考虑生成空 StringMap.tStringMap.empty 和采用 key[=53] 的 StringMap.add =]、关联的 和现有地图,以及 returns 添加了映射的新地图。

您可以轻松地使用fold_left将一张最初为空的地图逐步构建成一张完整的地图。剩下的唯一问题是您选择将什么值与列表中的每个字符串相关联。