我有一点问题:我想用OCaml解决this problem, 所以我尝试了这个 - >
-> let rec somme x = if ( nor (bool_of_int (x mod 3)) (bool_of_int (x mod 5))) then x + (somme x-1) else (somme x-1) ;;
val somme : int -> int = <fun>
-> somme 1000 ;;
Stack overflow during evaluation (looping recursion?).
我做错了什么?
我尝试了新代码:
let somme2 x = if (( nor (bool_of_int (x mod 3)) (bool_of_int (x mod 5)))) then x + somme (x-1) else somme (x-1) ;;
let somme x = if x = 0 then x else somme2 x ;;
同样的错误。
答案 0 :(得分:8)
1)你的记忆永远不会停止在开头添加if x == 0 then 0 else ...
之类的测试
2)你没有在x-1
附近加上括号,所以ocaml会读(somme x)-1
。改为写somme (x-1)
。
答案 1 :(得分:2)
正如其他人所指出的那样,你应该对基本情况进行测试。您可以使用模式匹配:
match x with
| 0 -> ...
| n -> ...;;
函数式语言通常与数学符号紧密相关,模式匹配实际上与您在纸上编写方程式的方式非常相似。
答案 2 :(得分:2)
这是解决问题的简单方法,也许它可以帮助您提高OCaml技能
(*generates a list of the multiples of num and stops at max*)
let gen_mult num max=
let rec gen i=
if i*num>=max then []
else (i*num)::gen (i+1)
in gen 1;;
let m3=gen_mult 3 1000;;
let m5=gen_mult 5 1000;;
(*sums the multiples of 3*)
let s3=List.fold_left (fun acc x->x+acc) 0 m3;;
(*sums the multiples of 5 except those of 3*)
let s5=List.fold_left (fun acc x->if x mod 3=0 then acc else x+acc) 0 m5;;
let result=s3+s5;;
答案 3 :(得分:2)
循环没有终止条件。修复你的代码:
let rec somme1 x =
if x <= 0
then 0
else if ((x mod 3) = 0) or ((x mod 5) = 0)
then x + (somme1 (x-1))
else somme1 (x-1);;
somme1 1000;;
为了改进你的代码,你要使你的函数拖尾递归。
let rec somme2 x accum =
if x <= 0
then accum
else if ((x mod 3) = 0) or ((x mod 5) = 0)
then somme2 (x-1) (accum+x)
else somme2 (x-1) accum
somme2 1000 0;;
两个版本之间的区别在于,在尾递归的情况下,递归调用的结果与函数的结果完全相同,因此不需要存储中间状态来完成后的计算。调用递归函数。当您致电somme1 1000;;
时,由于(1000 mod 5 == 0) or (1000 mod 3 == 0)
评估true
,您会收到递归调用1000 + (somme1 999)
,要完成,需要递归调用999 + (somme1 998)
。编译器必须将数字1000
和999
保持在堆栈中,直到somme1
完成执行,而不是(无终止条件),因此您的堆栈会填满尝试存储1000 + (999 + (996 + (995 + ...
。
这相当于((((0 + 1000) + 999) + 996) + 995) + ...
,但在这种情况下,没有处理递归调用结果所需的中间值(也就是说,递归调用的返回值与返回值相同)函数本身的值),因此不需要额外的堆栈空间。第二个版本以这种方式工作。如果它与第一个有相同的错误,它将不会用完堆栈,但会继续无限期地执行。这被认为是一种改进。 : - )
答案 4 :(得分:1)
我知道关于OCaml的zip,但看起来你的代码没有递归的终止条件。
答案 5 :(得分:0)
我在上面的代码中看不到任何终止条件?通常情况下,我希望递归停止x的某个值,可能是0或1.你的代码似乎没有包含这样的任何规定。
请记住,我对Neam承认的OCaml了解得多。
答案 6 :(得分:0)
尝试使用模式匹配和过滤参数 语法:
let f a= match a with
| a when (a=..) -> ...
| a when (a=..)-> ...
| _ -> ...;;
let f = function
p1 -> expr1
| p2 -> expr2
| p3 -> ...;;
解决方案:
let mult_3or5 a = match a with
a when ((a mod 3=0)||(a mod 5=0)) ->true
|_ ->false;;
let rec somme_mult_3or5 = function
a when (a=0) -> failwith "Indice invalide"
|a when (a=1) -> 0
|a -> if (mult_3or5 (a-1)=true) then ((a-1)+ somme_mult_3or5 (a-1))
else somme_mult_3or5 (a-1);;