如何从 ocaml 中另一个列表的索引更新列表索引

问题描述 投票:0回答:1

我是 ocaml 新手。我正在尝试实现 doMove :int list -> int list -> move -> int list。

第一个参数是罐子的卷列表, 第二个 - 描述罐子当前内容的列表,以及 第三——要执行的动作。

结果是一个描述 jar 更新内容的列表。您可以假设列表的长度始终相同,没有罐子包含的水多于其体积,并且移动中的索引是有效的。

例如调用doMove[5; 2] [5; 0] (Transfer (1, 0)) 应该产生一个列表 [3; 2].

我遇到的错误是 “该表达式具有 int list 类型,但预期的表达式为类型 整数”

type move = Transfer of int * int

let rec nth lst x =
  match lst with
  | [] -> raise (Failure "Not Found")
  | h :: t -> if x = 0 then h else nth t (x - 1)

let min x y = if x > y then y else x

let rec mapi f index list =
  match list with
  | [] -> []
  | x :: xs ->
    let result = f index x in
    result :: mapi f (index + 1) xs

let fst (a, _) = a

let snd (_, b) = b

let rec doMove jar_volumes jar_content move =
  let transfer_water_from_M_to_N m n jar_volumes jar_content =
    let jarM_volume_index = nth jar_volumes m in
    let jarN_volume_index = nth jar_volumes n in
    let jarM_content_index = nth jar_content m in
    let jarN_content_index = nth jar_content n in
    if jarM_content_index > 0 && jarN_content_index < jarN_volume_index then
      let compare_min_amount = min jarM_content_index (jarN_volume_index - jarN_content_index) in
      let new_jarM_content = jarM_content_index - compare_min_amount in
      let new_jarN_content = jarN_content_index + compare_min_amount in
      (new_jarM_content, new_jarN_content)
    else
      (jarM_content_index, jarN_content_index)
  in

  match move with
  | Transfer (m, n) ->
    let updated_jar_content =
      mapi (fun i content ->
        if i = m then fst (transfer_water_from_M_to_N m n jar_volumes jar_content)
        else if i = n then snd (transfer_water_from_M_to_N m n jar_volumes jar_content)
        else content)
      jar_content
    in
    updated_jar_content

我认为问题在于updated_jar_content。但是,我不知道如何解决它。有人可以帮我吗?非常感谢...

ocaml
1个回答
0
投票

在 utop 中快速运行代码可确认您所看到的错误与

jar_content
有关。

这是因为您的

mapi
函数需要三个参数:函数、索引和列表。您已经给了它两个:函数和列表。由于 OCaml 函数可以部分应用,因此您可以为其提供两个参数,但参数的顺序很重要。要修复此错误,请为其提供额外的
0
参数。

  match move with
  | Transfer (m, n) ->
    let updated_jar_content =
      mapi (fun i content ->
        if i = m then fst (transfer_water_from_M_to_N m n jar_volumes jar_content)
        else if i = n then snd (transfer_water_from_M_to_N m n jar_volumes jar_content)
        else content)
      0 jar_content
    in
    updated_jar_content;;

现在,可以编译了,但仍然没有产生正确的结果,因此还有更多工作要做。

utop # doMove [5;2] [5;0] (Transfer (1, 0));;
- : int list = [5; 0]
© www.soinside.com 2019 - 2024. All rights reserved.