OCaml,Collat​​z序列,无法打印结果

时间:2015-03-05 15:19:36

标签: ocaml

我正在尝试制作一个程序来计算从1到100的所有数字上的Collat​​z序列的长度。基本上如果我有一个奇数,我必须将它乘以3并加1(n * 3 + 1) ,如果我有一个偶数,我需要将它除以2(n / 2)然后继续这样做直到它变为1并最终打印出数字被除以2或乘以的次数3并添加1。 以下是我到目前为止的情况:

let stevec = ref 0;
let n = ref 1;
for i = 1 to 100 do
    n := i;
    while !n != 1 do
        if (n mod 2 = 0) then 
            stevec := !stevec + 1;
            n := !n / 2;
        if (n mod 2 = 1) then
            stevec := !stevec + 1;
            n := 3 * !n + 1;
    done
    print_int (stevec);
done;;

运行代码后,我得到一个语法错误,print_int得到下划线,所以我猜这有问题,但我甚至不确定。

1 个答案:

答案 0 :(得分:3)

您的代码存在一些问题,所以我们来看看它。

let stevec = ref 0;
let n = ref 1;

你不应该编写那种代码,因为;是一个表达式分隔符(你在这里使用它作为声明分隔符)。

正确的方法取决于您希望您的声明是本地的还是顶级的。

(* local declaration *)
let stevec = ref 0 in
let n = ref 1 in

(* toplevel declaration *)
let stevec = ref 0;;
let n = ref 1;;

然后键入while !n != 1 do。这不应该被用来在你的整数之间进行物理不等式,而你想要结构平等。好吧,由于OCaml对整数的行为,它也会起作用,但良好做法要求您使用<>而不是!=

现在让我们来看看你的循环体:

if (!n mod 2 = 0) then 
   stevec := !stevec + 1;
   n := !n / 2;
if (!n mod 2 = 1) then
   stevec := !stevec + 1;
   n := 3 * !n + 1;

请注意没有任何fi或右括号?这是因为在OCaml中,只执行then之后的下一个表达式。 ;的优先顺序并不像您希望的那样。您可以使用parens或更明确的begin ... end构造。为了证明begin ... end有效,我用else语句替换了你的第二个测试。

if (!n mod 2 = 0) then
   begin
    stevec := !stevec + 1;
    n := !n / 2;
   end
else
   begin
    stevec := !stevec + 1;
    n := 3 * !n + 1;
   end

最后while ... done本身就是一个表达式,你应该在它的末尾添加一个;

这就是你如何从代码中删除错误 然而...

这显然不是正确的方式&#34;在OCaml中做到这一点。 FP的主要特点是它与数学的接近程度,你在这里试图定义一个数学函数。因此,让我们以函数方式执行此操作:

let is_even x = (x mod 2) = 0;;
let rec collatz counter n =
  if n = 1
  then counter
  else collatz (counter+1) (if is_even n then n/2 else 3*n+1);;
let () =
 for i = 1 to 100 do
  print_int (collatz 0 i);
  print_newline ();
 done;;

看起来不那么好吗?当然可以随意要求澄清。