英文:
Int64 usage in recursive functions
问题
以下是要翻译的代码部分:
let rec f n:int64=
if n<1 then 1L
else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
Printf.printf "%d\n"(f i)
done;
但问题是,递归函数似乎不接受Int64
值,似乎希望使用Int
而不是,尽管我将n
标记为int64
:
File "/proc/self/fd/0", line 3, characters 19-21:
3 | else (4*n-2)*f((n-1L))/(n+1L)
^^
Error: This expression has type int64 but an expression was expected of type
int
exit status 2
是否有一种方法可以确保我在递归中使用int64数字?
英文:
I have the following code written in Ocaml to try and generate the first 50 catalan numbers:
let rec f n:int64=
if n<1 then 1L
else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
Printf.printf "%d\n"(f i)
done;
But the problem is that the recursion function doesn't seem to accept Int64
values and seems to want Int
instead despite me notating n
as int64
:
File "/proc/self/fd/0", line 3, characters 19-21:
3 | else (4*n-2)*f((n-1L))/(n+1L)
^^
Error: This expression has type int64 but an expression was expected of type
int
exit status 2
Is there a way to ensure I can int64 numbers here with recursion?
答案1
得分: 2
你的问题并不是递归本身,而是OCaml中的运算符具有强类型。所以-
运算符的类型是int -> int -> int
。
不需要过多纠结于语法,最简单的修复方法可能是使用Int64模块的命名函数。例如,你可以使用Int64.sub
而不是-
。
你可以使用表示法Int64.(... <expr> ...)
来避免重复模块名称。如果你按照这种方式重写你的代码,会得到如下结果:
let rec f (n : int64) : int64 =
Int64.(
if n < 1L then 1L
else
mul (sub (mul 4L n) 2L)
(f (div (sub n 1L) (add n 1L)))
)
查看这个函数计算的结果,它们看起来并不像卡塔兰数。事实上,第50个卡塔兰数太大,无法表示为int64值。
所以还有一些工作要做。但这是克服你遇到的问题的方法(依我之见)。
如果你真的想要处理如此大的数字,你可能需要查看Zarith模块。
英文:
Your problem isn't recursion per se, it's that the operators in OCaml are strongly typed. So the -
operator is of type int -> int -> int
.
Without getting into lots of fussing with the syntax, the easiest fix is probably to use the named functions of the Int64 module. You can use Int64.sub
rather than -
, for example.
You can use the notation Int64.(... <expr> ...)
to avoid repeating the module name. If you rewrite your code this way, you get something like this:
let rec f (n : int64) : int64 =
Int64.(
if n < 1L then 1L
else
mul (sub (mul 4L n) 2L)
(f (div (sub n 1L) (add n 1L)))
)
Looking at the results computed by this function, they don't look like Catalan numbers to me. In fact the 50th Catalan number is too large to be represented as an int64 value.
So there is still some work to do. But this is how to get past the problem you're seeing (IMHO).
If you really want to work with such large numbers, you probably want to look at the Zarith module.
答案2
得分: 1
作为对Jeffrey答案的额外建议提交:无论是使用Int64
还是Zarith
,您可以创建一个定义算术运算符的模块,然后在本地打开该模块以简化您的代码。
例如:
module Int64Ops =
struct
let ( + ) = Int64.add
let ( - ) = Int64.sub
let ( * ) = Int64.mul
let ( / ) = Int64.div
end
let rec f n =
Int64Ops.(
if n < 1L then 1L
else (4L * n - 2L) * f (n - 1L) / (n + 1L)
)
或者您可以使用一个functor,以便更轻松地处理多种不同类型的数字。
module type S =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module BasicArithmeticOps (X : S) =
struct
type t = X.t
let ( + ) = X.add
let ( - ) = X.sub
let ( * ) = X.mul
let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L
英文:
Submitted as an additional suggestion to Jeffrey's answer: whether using Int64
or Zarith
, you might create a module defining arithmetic operators and then locally open that to clean up your code.
E.g.
module Int64Ops =
struct
let ( + ) = Int64.add
let ( - ) = Int64.sub
let ( * ) = Int64.mul
let ( / ) = Int64.div
end
let rec f n =
Int64Ops.(
if n < 1L then 1L
else (4L * n - 2L) * f (n - 1L) / (n + 1L)
)
Or you could use a functor to make it easier to work with multiple different types of numbers.
module type S =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module BasicArithmeticOps (X : S) =
struct
type t = X.t
let ( + ) = X.add
let ( - ) = X.sub
let ( * ) = X.mul
let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论