繁体   English   中英

Ocaml 取函数

[英]Ocaml take function

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

有人可以帮忙吗?

这是 tl 函数 -

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

这才是真正的 take 函数——

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))

该消息的原因是您遗漏了一对括号,因此您试图将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的头部的列表,其尾部是从xs的尾部取出k - 1元素的结果。

也就是说,

let rec take k xs = match k with
    | 0 -> []
    | k -> match xs with
           | [] -> failwith "take"
           | y::ys -> y :: (take (k - 1) ys)

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

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

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

let rec take n list = ...

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

  • n = 0 : 只返回一个空列表
  • n > 0 : 取一个元素并用n - 1递归
  • n < 0 :否定的情况很容易被遗漏,但如果你不小心,你很容易在运行时输入无效输入的无限递归。 幸运的是,在这里,我们将使用异常并使事情在递归链中终止(例如,这就是Moldbino 的答案中发生的情况),但其他函数可能表现不佳 take一些实现,当给定负数时,尝试有用并从列表的末尾获取n 个元素。 在这里,我们将简单地将任何不是严格为正的 n 视为 if 为 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 ,它构成了我们想要返回的列表的头部。 列表的尾部是由xsn-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 [];;

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

更新

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

let myfun k xs = function ...

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

快速修复只是删除xs

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM