我有一个递归函数fact
,可以从其中的表达式或其外部的表达式调用。
我想将fact
与变量v
相关联,以便每次从外部(另一个函数)调用fact
时,{{1 }}已初始化,其值可在v
内更改,但从内部调用fact
时永远无法初始化。
以下代码符合我的需要,但有一个问题是fact
被定义为全局变量,我必须在从外部调用v
之前执行v := init
,我这样做找不到美丽。
fact
有人能想到更好的实施吗?
答案 0 :(得分:5)
您可以隐藏包含函数体内的函数和值定义,如下所示:
open Printf
let init = 100
let fact n =
let rec fact counter n =
incr counter;
if n <= 0 then 1 else n * fact counter (n - 1)
in
let counter = ref init in
let result = fact counter n in
(result, !counter)
let main () =
let x, count = fact 3 in
printf "%i\n" x;
printf "counter: %i\n" count (* 104 is expected *)
let () = main ()
答案 1 :(得分:3)
您可以调整Martin的解决方案,以便在各种调用之间共享数据:
let fact =
let counter = ref 0 in
fun n ->
let rec fact = ... in
fact n
我们的想法是将let fact = fun n -> let counter = ... in ...
转换为let fact = let counter = ... in fun n -> ...
:计数器初始化一次,而不是每次调用fact
。
这种风格的典型例子是:
let counter =
let count = ref (-1) in
fun () ->
incr count;
!count
请注意,如果函数是多态的,你可能会遇到输入错误:let foo = fun n -> ...
总是被推广到多态函数中,let foo = (let x = ref ... in fun n -> ...)
不是,因为它不健全,所以{ {1}}不会有多态类型。
您甚至可以将上面的计数器示例概括为计数器工厂:
foo
对于let make_counter () =
let count = ref (-1) in
fun () ->
incr count;
!count
的每次调用,您都会获得一个新计数器,这是一个在调用时共享状态的函数,但其状态独立于之前的make_counter ()
计数器创建。
答案 2 :(得分:1)
使用Ocaml的对象,您可以:
class type fact_counter = object ('self)
method get : int
method set : int -> unit
method inc : unit
method fact : int -> int
end;;
class myCounter init : fact_counter = object (self)
val mutable count = init
method get = count
method set n = count <- n
method inc = count <- count + 1
method fact n =
self#inc;
if n <= 0 then 1 else n * self#fact (n - 1)
end;;
然后你可以获得:
# let c = new myCounter 0;;
val c : myCounter = <obj>
# c#fact 10;;
- : int = 3628800
# c#get;;
- : int = 11
# c#set 42;;
- : unit = ()
# c#fact 10;;
- : int = 3628800
# c#get;;
- : int = 53
我希望您能轻松了解如何调整myCounter
以包含fib
...