-1

我正在尝试创建一个返回列表中前 k 个元素的值的函数。这是行不通的。我不知道为什么。

有人可以帮忙吗?

这是 tl 功能 -

let tl j = match j with
  | [] -> []
  | x :: xs -> xs;;

这是真正的拍摄功能-

let rec take k xs = function
  | [] -> failwith "take"
  | x :: xs -> if k = List.length ([x] @ xs) then [x] @ xs
               else [x] @ take List.length xs (tl(List.rev.xs))
4

3 回答 3

3

您的函数接受一个整数n,并从列表list 中获取n 个元素,该列表包含 list 的n个元素。所以你的签名很可能是:

int -> 'a list -> 'a list = <fun>

您可能已经猜到该函数将被递归定义,因此您已经可以像这样编写函数的定义:

let rec take n list = ...

您必须建立一个列表,但让我们首先考虑n的三大类值:

  • n = 0:只返回一个空列表
  • n > 0:取一个元素并用n - 1递归
  • n < 0 : 否定的情况很容易被忽略,但如果你不小心,你很容易在运行时输入无效输入的无限递归。幸运的是,在这里,我们将使用异常并使事情沿递归链终止(例如,这就是Moldbino 的 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 [];;
于 2016-10-22T16:49:50.270 回答
3

该消息的原因是您遗漏了一对括号,因此您尝试将List.length其作为第一个参数传递给take.

另一个问题是你定义了一个带有三个参数的函数——你的定义说take k xs返回一个带有列表参数(未命名)的函数。

第三个问题是take (List.length xs) (tl(List.rev xs))
这试图从尾部xs(并且由于某种原因,相反)中多取一个元素。

所以我打算完全重写它。

首先,你不应该使用List.length这个。
List.length几乎从来都不是一个好的解决方案。)
您只需要关心列表是否为空,不管它有多长。

现在,一个更正式的定义:

take k xs

  • 如果k为 0,则为空列表
  • 否则,如果xs是空列表,则为错误
  • 否则,它的第一个元素是 的头部xs,其尾部是k - 1从 的尾部获取元素的结果xs

那是,

let rec take k xs = match k with
    | 0 -> []
    | k -> match xs with
           | [] -> failwith "take"
           | y::ys -> y :: (take (k - 1) ys)
于 2016-10-22T16:39:33.977 回答
2

您的直接问题是您需要在 . 周围加上括号(List.length xs)。该代码还在所有情况下都将空输入列表视为错误,这是不正确的。如果所需长度k为 0,则空列表是合法输入。

更新

您的定义中还有一个额外的参数。如果你这样说:

let myfun k xs = function ...

该函数myfun有3个参数。前两个是命名k的,xs第三个是function表达式的隐含部分。

快速修复只是删除xs.

我认为您可能在递归调用中要求错误数量的元素take。反正有什么要看的。

于 2016-10-22T16:10:15.347 回答