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

OCaml, Collatz sequence, can't print the result

我正在尝试编写一个程序来计算从 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 有下划线,所以我想这有问题,但我什至不确定。

你的代码有几个问题,我们来看看。

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 之后的下一个表达式。 ; 的优先级并不如您所愿。您可以使用括号或更明确的 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 本身就是一个表达式,你应该在它的末尾加上一个 ;

这就是您从代码中删除错误的方法。
然而...

这显然不是 "right way" 在 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;;

这样不是更好看吗?当然,请随时要求任何澄清。