2017-04-17 50 views
2
数组的前n个元素

我在ocaml的以下功能,总结第一c元素作为参数传递的数组:遍历OCaml中

let rec sum_array c a = 
    if c < 0 then 0 
    else a.(c) + sum_array (c - 1) a;; 

我碰巧知道什么阵a是先进的,所以我想设置这个。我试过了:

fun c -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
    let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1);; 

但OCaml抱怨模糊的'错误:语法错误',这是超级有用的。

  1. 如何解决此功能定义?我如何指定我要返回sum_array的值?
  2. 我怎样才能让OCaml报告更多有用的错误消息?

回答

5

从某种意义上说,您的问题是您在错误的位置添加fun c -> ...

假设您有这样的功能:

let f count = 
    (count + 72 - 1)/72 

如果你想象的硬编码值72是你想预先计算,你可以重写的功能如下:

let f = 
    let line_length = 72 in 
    fun count -> (count + line_length - 1)/line_length 

您的代码将数组放在函数的主体之前,但它应该位于内部,位于let和新的内部函数定义之间。

你的情况特别棘手,因为你的函数是递归的。因此,您无法切换到fun c -> ...表单。相反,您可以在本地保留原始的基于let的定义。对于人为的例子,它是这样的:

let f = 
    let line_length = 72 in 
    let inner_f count = 
     (count + line_length - 1)/line_length 
    in 
    inner_f 

(作为一个方面评论,您的代码求和数组,而不是第一个C元件的第一C + 1种元素。)

3

误差消息出现在;;上,因为let没有in只允许作为最外面的语句。为了使你的表达评估,你需要添加in sum_array c

fun c -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
    let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1) 
    in sum_array c;; 
- : int -> int = <fun> 

这可以通过降低对c抽象简化:

let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
    let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1) 
    in sum_array;; 

在这两种情况下,sum_array没有绑定在顶层。要么你与另一个let sum_array =绑定它......,你拉的int_array绑定的定义内sum_array(如@Jeffrey斯科菲尔德提议的),或者你在顶层结合int_array定义之前sum_array

let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] 

let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1) 
;; 
0

这个答案可能看起来有点冗长,但那只是因为我从你的错误中看到了OCaml的一些基本概念中的某些缺乏理解。这可能是一个很好的机会来澄清一些事情。

范围和顺序OCaml中

您可能会或可能不会已经已经明白这个话题。由于它们是接下来的基础,我仍然不得不详细说明这一点。

想想你将如何测试代码:

let rec sum_array c a = 
    if c < 0 then 0 
    else a.(c) + sum_array (c - 1) a 
in 
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |]   ;; 

我假定你所熟悉的普通的编程语言。把它放在一个Java方法:

//Java version 
int a = 1; 
int b = 1; 
int c = a + b; 

将被翻译成的OCaml的代码:

(* OCaml version *) 
let a = 1 in 
let b = 1 in 
let c = a + b in 
c  ;; 

他们是不是所有的不同。乍一看,OCaml代表测序的方式(即;)似乎很乏味。但随着你的函数式编程之旅的继续,你会更加了解这种机制的重要性。

错误的逻辑

至于结果表明:

let rec sum_array c a = 
    if c < 0 then 0 
    else a.(c) + sum_array (c - 1) a 
in 
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |] ;; 
(* - : int = 6 *) 

你在这里做的逻辑是一个小故障。你的功能增加了一个以上的元素。修复很简单:

let rec sum_array c a = 
    if c = 0 then 0 
    else a.(c - 1) + sum_array (c - 1) a 
in 
sum_array 2 [| 1 ; 2 ; 3 ; 4 ; 5 |] ;; 
(* - : int = 3 *) 

它的工作现在。该函数现在总结数组的第一个元素。

如何存储[| 1; 2; 3; 4; 5 |]添加到函数中,这样只需要参数n

我想这就是你所说的意思:我碰巧预先知道阵列a。

这里是简单的代码来做到这一点非常小的变化:

sum_array 3;; 
(* - : int = 6 *) 

看到这里的变化不大,只是用另一种let ... in

let rec sum_array c = 
let a = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
    if c = 0 then 0 
    else a.(c - 1) + sum_array (c - 1)   ;; 

然后你就可以像这样运行它在函数定义中硬编码a的定义。这正是如何在java中做同样的事情。

有人说,你自己的代码有什么问题?

您的代码:

fun c -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
    let rec sum_array c = 
     if c < 0 then 0 
     else int_array.(c) + sum_array (c - 1);; 

失败的原因有两个:

  • 如影随形:它看起来像,该函数只有c作为参数,但实际上它是通过后不做任何处理c在。这是因为您的函数sum_array(这是外部整体函数的辅助函数)有另一个相同的名称参数c,并且此参数会影响绑定或最外面的参数c的定义。
  • 范围:在这个大功能的定义范围内,您定义了int_arraysum_array。但它们都是本地名称,并且您没有返回任何内容。回想一下,函数的返回值是整个表达式在箭头右侧的值。这种情况下的价值是什么?除了一些局部变量的定义之外,什么都没有,只要函数结束就会过期。

这是正确的代码:

fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
     let rec sum_array c = 
      if c < 0 then 0 
      else int_array.(c) + sum_array (c - 1) 
     in sum_array arg 

但还有另一个问题,上述这种功能,是一款功能。这意味着这是一个价值。如果你现在没有将一个值绑定到一个变量上,你现在就使用它,或者你失去了它的踪迹。因此,这里要做的更好的事情是:

let sum_first_n = 
fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
     let rec sum_array c = 
      if c < 0 then 0 
      else int_array.(c) + sum_array (c - 1) 
     in sum_array arg  ;; 

现在,您可以像调用其他函数一样调用它。

当然,我仍然在这段代码中使用错误的逻辑。解决这个问题,我们有:

let sum_first_n = 
fun arg -> let int_array = [| 1 ; 2 ; 3 ; 4 ; 5 |] in 
     let rec sum_array c = 
      if c = 1 then int_array.(0) 
      else int_array.(c - 1) + sum_array (c - 1) 
     in sum_array arg  ;; 

sum_first_n 3;; 
(* - : int = 6  *) 

现在一切正常。

如何做到更多功能?

如果给出List的参数而不是数组,那该怎么办?你如何做到没有突变?

这是一种很好的做法,可以帮助您更快地掌握OCaml。

下面是代码:

let rec sum_array c l = match c,l with 
    | _, [] | 0, _ -> 0 
    | (_, hd::tl) -> hd + sum_array (c-1) tl 
in sum_array 4 [1;2;3;4;5;6]  ;; 
+0

我不知道这是为什么下来投了票,但谢谢你,这么一个竞争的答案! –