OCaml,Collatz 序列,无法打印结果
OCaml, Collatz sequence, can't print the result
我正在尝试编写一个程序来计算从 1 到 100 的所有数字的 Collatz 序列的长度。基本上,如果我有一个奇数,我必须将它乘以 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;;
这样不是更好看吗?当然,请随时要求任何澄清。
我正在尝试编写一个程序来计算从 1 到 100 的所有数字的 Collatz 序列的长度。基本上,如果我有一个奇数,我必须将它乘以 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;;
这样不是更好看吗?当然,请随时要求任何澄清。