我在OCaml中有以下函数,它将作为参数传递的数组中的第一个c
元素相加:
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抱怨模糊的“错误:语法错误”,这非常有帮助。
sum_array
的值?答案 0 :(得分: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 + 1个元素,而不是第一个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 Scofield建议的那样),或绑定{{1}在定义int_array
:
sum_array
答案 2 :(得分:1)
这个答案可能看起来有点冗长,但这仅仅是因为我从你的错误中看到某些基本的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 *)
现在可行。该函数现在总结了数组的第一个n
元素。
n
?我认为这就是你的意思:我碰巧事先了解了数组。
这里有一些简单的代码可以做很少的改变:
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) ;;
然后你可以像这样运行它:
sum_array 3;;
(* - : int = 6 *)
请参阅此处的小改动只是使用另一个let ... in
来对函数定义中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
传入之后无效。这就是&#39 ; s因为你的函数c
(它是外部整体函数的辅助函数)有另一个同名参数sum_array
,并且这个参数遮蔽了最外面的参数{{的绑定或定义。 1}}。c
和int_array
。但它们都是本地名称,你没有返回任何东西。回想一下,函数的返回值是箭头右侧的整个表达式的值。在这种情况下,这个价值是多少?除了一些局部变量的定义之外,什么都没有,一旦函数结束就会过期。这是正确的代码:
sum_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 ;;
现在一切正常。
如果给出List的参数而不是数组,该怎么办?如果没有变异,你会怎么做?
这是帮助您更快地跟踪OCaml的好习惯。
以下是代码:
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 *)