在OCaml中返回列表的第n个元素?

10

我刚接触Ocaml,想确认如何使用递归函数执行简单的功能,例如返回列表的第n个元素?

原型类似于get_nth (list, n),其中int list * int -> int

例如get_nth ([1,2,3], 1) -> 2

谢谢


1
这真的听起来像是一个作业问题。如果你能展示一些你尝试过但并没有达到预期效果的代码,那会很有帮助。 - Jeffrey Scofield
4个回答

16

你可能没有注意到,但是 List.nth 函数已经在 List 模块 中存在。

如果你想使用递归来编写它:

let rec get_nth = function
    | [], _ -> raise (Failure "get_nth")
    | _, n when n < 0 -> raise (Invalid_argument "get_nth")
    | x::_, 0 -> x
    | x::xs, n -> get_nth(xs, n-1)

6

在OCaml中,像这样使用元组作为参数并不常见。通常你会使用柯里化(currying)并像这样定义函数:

let get_nth list n = ...

这将具有签名'a list -> int -> 'a。还要注意,您在这里有一个'a参数,这意味着没有真正的理由只限制函数为整数。
现在让我们看看问题。如果您想获得零元素,您的函数会是什么样子?
let get_nth list 0 = List.head list (* this is not actually valid in OCaml *)

现在,如果你有一个函数用于从m个元素的列表中获取第n个元素(注意:n > m),那么你如何使用该函数构建另一个函数,以获取m+1个元素的第n+1个元素?让这个针对n+1个元素的函数为get_nth'

let get_nth' list n' = get_nth (List.tail list) (n'-1)

现在您只需要将两者结合起来,就完成了。最后一部分就留给您自己处理。
如果您遵循这个建议,您将得到一个比必要更为复杂的东西。但是这样做更容易理解正在发生的事情。

很遗憾,我担心你的尝试比必要的更加混乱。Ocaml模式匹配本身已经相当直观易懂了。 - Pandemonium

3

(依我之见) 不使用元组的更简单的解决方案是:

let rec get_nth mylist index = match mylist with
    | [] -> raise (Failure "empty list")
    | first::rest -> 
        if index = 0 then first 
        else get_nth rest (index-1)
;;

1
我本来会把这个作为正确答案。在 Ocaml 函数中使用元组作为参数并不是很惯用,需要进行分配。 - Pandemonium

0

我在这里读到,使用Result而不是抛出错误可能更好,因为你不必使用try ... with。(代码由@Omar编辑)

let rec get_nth mylist index = match mylist with
    | [] -> Error "empty list"
    | first::rest -> 
        if index = 0 then Ok first 
        else get_nth rest (index-1)
;;

let result [1; 2; 3] 2 in 
    match result with
    | Error reason -> print_string reason
    | Ok num -> print_int num
;;

ResultCore.Std 的一部分,如果我没记错的话。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接