Ocaml:函数计算两个整数并返回范围内所有整数的列表

发布于 2024-12-01 12:46:02 字数 298 浏览 1 评论 0原文

该函数接受两个整数并返回 [a,b] 范围内所有整数的列表,

这是我编写的解决方案。

let rec range_rec l a b = 
  if (a=b) then l@[b]
  else range_rec (l@[a], a+1, b);;

let range a b = range_rec [] a b;;

我遇到错误“错误:此表达式的类型为 int list * int * int,但表达式应为 int 类型”。有人可以解释一下为什么我会收到此错误吗?

谢谢。

This function takes two integers and returns the list of all integers in the range [a,b]

This is the solution that I wrote.

let rec range_rec l a b = 
  if (a=b) then l@[b]
  else range_rec (l@[a], a+1, b);;

let range a b = range_rec [] a b;;

I'm hitting an error "Error: This expression has type int list * int * int but an expression was expected of type int". Can someone throw some light on why am I getting this error?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

昵称有卵用 2024-12-08 12:46:02

它应该看起来像这样:

let rec range_rec l a b = 
  if a = b then l @ [b]
  else range_rec (l @ [a]) (a + 1) b;;

let range a b = range_rec [] a b;;

我所做的:

  1. loop 更改为 range_rec
  2. 更改 (l@[a], a+1, b)(l @ [a]) (a + 1) b。第一个是三元组,第二个是柯里化函数的 3 个参数。
  3. 请注意,if (a = b) then 可以写为 if a = b then

最后,通过“向后”循环使用 :: 而不是 @ 可以使该函数更加高效。例如,像加斯切(gasche)所展示的那样。

It should look like this:

let rec range_rec l a b = 
  if a = b then l @ [b]
  else range_rec (l @ [a]) (a + 1) b;;

let range a b = range_rec [] a b;;

What I've done:

  1. Changed loop to range_rec
  2. Changed (l@[a], a+1, b) to (l @ [a]) (a + 1) b. The first is a triplet and the second is 3 arguments to a curried function.
  3. Notice that if (a = b) then can be written as if a = b then.

Last, the function can be made more efficient by using :: instead of @ by looping "backwards". For example like gasche have shown.

蹲在坟头点根烟 2024-12-08 12:46:02

从性能角度来看,l @ [elem] 操作非常糟糕:因为 a @ ba 的长度呈线性关系,因此添加一个元素到列表末尾与列表长度呈线性关系,使整个 range_rec 定义在 |ba| 中呈二次方关系。解决方法是更改​​代码,以便可以使用恒定时间 elem::l 操作。

let rec range a b =
  if a > b then []
  else a :: range (a + 1) b

您可以进行其他优化,例如使其成为尾递归,但至少该解决方案的复杂性是正确的。

The l @ [elem] operation is terrible from a performance perspective : as a @ b is linear in the length of a, adding an element to the end of list is linear in the length of the list, making your whole range_rec definition quadratic in |b-a|. The way to go is to change your code so that you can use the constant-time elem::l operation instead.

let rec range a b =
  if a > b then []
  else a :: range (a + 1) b

You may make additional optimizations such as making it tail-recursive, but at least the complexity of this solution is right.

素染倾城色 2024-12-08 12:46:02

为了改进gasche已经建议的解决方案,可以将其设为尾递归。

let int_range a b =
  let rec int_range_rec l a b =
    if a > b then l
    else int_range_rec (b :: l) a (b - 1)
  in (int_range_rec [] a b);;

To improve on the solution already suggested by gasche, this can be made tail-recursive.

let int_range a b =
  let rec int_range_rec l a b =
    if a > b then l
    else int_range_rec (b :: l) a (b - 1)
  in (int_range_rec [] a b);;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文