红框里的类型信息为什么不是:'a -> 'a -> 'a -> 'a -> 'a
?
我认为所有参数和返回值都应该是同一类型,并且 utop 确实确认它们都是同一Z.t
类型。
utop # let rec fib_acc = fun n -> fun n_1 -> fun n_2 -> fun acc ->
if (Z.equal n Z.one) || (Z.equal n (Z.of_int 2))
then acc
else fib_acc (Z.add n Z.minus_one) n_2 (Z.add n_1 n_2) (Z.add n_1 n_2);;
val fib_acc : Z.t -> Z.t -> Z.t -> Z.t -> Z.t = <fun>
我们对
Z.add
、Z.equal
、和的类型了解多少Z.one
?Z.minus_one
Z.of_int
如果您想要得出这样的结论,那么您需要这些信息:
n, n_1, n_2
并且acc
所有都有类型Z.t
。Z.add
在不知道函数和 的类型的情况下Z.equal
,我们可以得出acc
和 返回值具有相同的类型,因为 分支then acc
,并且我们可以得出n_1
和n_2
具有相同的类型,因为n_2
代替了n_1
递归调用中的 。这解释了 的类型'a -> 'b -> 'b -> 'c -> 'c
。据推测,
utop
可以访问Z.add
和的类型Z.equal
,但为您提供类型提示的软件'a -> 'b -> 'b -> 'c -> 'c
无法访问该信息。除了stef 的回答之外,您似乎犯了一个新 OCaml 程序员经常犯的错误:在源代码文件中使用顶级指令。
#require
您需要确保正确编译以链接 Zarith 库,而不是使用。您可以使用 dune,但目前这可能有点过头了。目前来说,
ocamlfind
它可以很好地完成工作。您的源文件现在是:
Z
但如果我们局部打开并局部重新定义,这可能会变得更易读=
。加minus_one
也可以是减one
。还要注意,您传递的值
n_2
和acc
是相同的。acc
参数是不必要的。您的函数可以简化。但您可能也想隐藏最后两个参数,因为您总是希望在第一次调用时提供一些设定值。
Z.(fib_acc (of_int 67) (of_int 34) (of_int 3))
例如,调用就没有意义了。