递归函数返回列表中的所有值(OCaml语言)

4
我需要一个递归返回 (不是打印) 列表中所有值的函数。然而,每次我尝试编写此功能时,我的函数都会返回一个列表。
let rec elements list = match list with
 | [] -> []
 | h::t -> h; elements t;;

我需要在另一个我编写的函数中每次使用返回的每个元素,因此我需要逐个使用这些元素,但我无法解决这部分。任何帮助将不胜感激。

2个回答

3
你的函数等效于:
let rec elements list = 
  match list with 
    | [] -> []
    | h :: t -> elements t

这是因为a ; b会先计算a(并丢弃结果),然后计算并返回b。显然,这等价于:
let elements (list : 'a list) = []

这不是一个非常有用的函数。

然而,在尝试解决此问题之前,请了解 Objective Caml函数只能返回一个值。 返回多个值是不可能的。

有方法可以解决这个限制。 一种解决方案是将您希望返回的所有值打包成单个值:通常是元组或列表。 因此,如果您需要返回任意数量的元素,则应将它们打包到列表中,并让调用代码处理该列表:

let my_function () = [ 1 ; 2; 3; 4 ] in (* Return four values *)
List.iter print_int (my_function ())    (* Print four values *)

另一个不太常见的解决方案是提供一个函数,并在每个结果上调用它:
let my_function action = 
  action 1 ;
  action 2 ;
  action 3 ;
  action 4
in
my_function print_int

这种方法可能不够灵活,但可以认为比返回列表更快:列表可以过滤、排序、存储...

谢谢您的回复。我一直在考虑用两个函数分两步来完成,就像您描述的那样,但我的问题是如何逐个检索每个元素。我应该再具体一些。我的主要函数是一个子集函数,在这个函数中,我需要确定列表a是否是列表b的子集。我需要以多态的方式编写此函数,但现在我只能想出如何使用整数列表来完成它。 - Atticus
问题出在我写了一个函数来返回列表的第一个元素:let head list = match list with h::t -> h | [] -> 0。由于我必须考虑空列表,所以我返回0,而OCaml确定这个函数需要一个整数列表。由于子集函数需要是多态的,我无法预先知道对于空集应该返回什么,是0、"null"还是其他什么。因此,这限制了我只能使用整数列表。 - Atticus
在这种情况下(空列表应该返回什么),只需引发一个错误:(failwith“error”)。 - gasche
3
我认为你在这件事上完全朝着错误的方向前进。如果你在写子集函数时有问题,我建议你提出一个关于这个问题的问题 - 你会得到更清晰、更适合你实际问题的答案(例如let subset a b = List.for_all (fun i -> List.mem i b) a),同时还能对你已经写的代码进行建设性的评论。 - Victor Nicollet

1

你的问题有点令人困惑 - 你想要一个返回列表中所有值的函数。那么,返回可变数量的值最简单的方法就是使用列表!你是否尝试模拟Python生成器?OCaml没有类似于yield的东西,但通常通过将函数“传递”给值(使用iterfoldmap)来实现相同的功能。

你当前编写的代码在Python中等价于:

def elements(list):
    if(len(list) == 0):
        return []
    else:
        list[0]
        return elements(list[1:])

如果你正在尝试做这个:

def elements(list):
    if(len(list) > 0):
        yield list[0]
        # this part is pretty silly but elements returns a generator
        for e in elements(list[1:]):
            yield e

for x in elements([1,2,3,4,5]):
    dosomething(x)

在OCaml中的等价写法如下:

List.iter dosomething [1;2;3;4;5]

如果您正在尝试确定列表a是否是列表b的子集(正如我从您的评论中了解到的),那么您可以利用List.memList.for_all

List.for_all (fun x -> List.mem x b) a

fun x -> List.mem x b 定义了一个函数,如果值 x 等于 b 中的任何元素,则返回 true(是成员)。List.for_all 接受一个返回布尔值的函数(在我们的情况下,刚刚定义的成员函数)和一个列表。它将该函数应用于列表中的每个元素。如果该函数对列表中的每个值都返回 true,则 for_all 返回 true。

所以我们所做的就是:对于 a 中的所有元素,检查它们是否是 b 的成员。如果您有兴趣自己编写这些函数,那么我建议阅读 list.ml 的源代码,它(假设 *nix)可能位于 /usr/local/lib/ocaml 或 /usr/lib/ocaml。


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