您的函数接受一个整数 n,并从列表 list 中获取 n 个元素,该列表包含 list 的 n 个第一个元素。
所以你的签名很可能是:
int -> 'a list -> 'a list = <fun>
您可能已经猜到该函数将被递归定义,因此您已经可以像这样编写函数的定义:
let rec take n list = ...
您必须建立一个列表,但让我们首先考虑 n 的三大类值:
-
n = 0 : 只返回一个空列表
-
n > 0 : 取一个元素并用 n - 1 递归
-
n : 否定的情况很容易漏掉,但是如果你不小心的话,很容易在运行时输入无效输入的无限递归。幸运的是,在这里,我们将使用异常并使事情沿递归链终止(例如,moldbino's answer 中发生的情况),但其他函数可能表现不佳。
take 的一些实现,当给定一个负数时,尝试有用并从列表末尾获取 n 个元素。
在这里,我们将简单地将任何不是严格正数的 n 视为 null。
空或负N
当我们从列表中取出零个元素时,这意味着我们返回空列表:
let rec take n list =
if n > 0
then ...
else [];;
正面N
现在,我们考虑从列表中获取 n > 0 个元素的情况。
根据列表的递归定义,我们必须考虑每种可能的列表,即空列表和非空列表。
let rec take n list =
if n > 0
then
match list with
| [] -> ...
| x :: xs -> ...
else [];;
当我们想从一个空列表中取出 n > 0 个元素时会发生什么?
我们失败了。
let rec take n list =
if n > 0 then
match list with
| [] -> failwith "Not enough elements in list"
| x :: xs -> ...
else [];;
现在,递归的一般情况。我们有一个非空列表,并且 n > 0,所以我们知道我们可以从列表中获取至少一个元素。
这个值是x,它构成了我们要返回的列表的头部。列表的尾部是由 xs 的 n-1 个元素组成的,take 本身很容易计算出来:
let rec take n list =
if n > 0 then
match list with
| [] -> failwith "Not enough elements in list"
| x :: xs -> x :: (take (n - 1) xs)
else [];;