我想内心“让”,但有两个功能。
我现在有一个功能
let fresh_var () =
let r = ref 0 in
r := !r + 1 ; Var !r;;
我想添加第二个函数,以便它可以更改r,但r对于程序的其余部分保持不可见。类似的东西:
let r = ref 0 in
let fresh_var () = r := !r + 1 ; Var !r
and let refresh () = r := 0
但由于语法错误,上面的部分不起作用。
如何在OCaml中实现这个想法?
答案 0 :(得分:3)
您可以简单地创建一个返回一对函数的函数:
let get_fresh_and_reset () =
let r = ref 0 in
(fun () -> incr r; !r), (fun () -> r := 0)
let fresh, reset = get_fresh_and_reset ()
另请注意,正确的语法是:=
而不是=:
。
修改强>
如上所述@Virgile,如果您不需要多个计数器,则可以简化:
let fresh_var, refresh =
let r = ref 0 in (fun () -> incr r; !r), (fun () -> r:=0)
答案 1 :(得分:2)
这不是OCaml中的工作方式。 本地定义正是本地的。它们不能在函数之间共享。
如果你想抽象部分实现,我建议改用模块。
module Incrementer : sig
val next : unit -> int
val reset : unit -> unit
end = struct
let r = ref 0
let next () =
r := !r + 1;
!r
let reset () =
r := 0
end
请参阅下面的操作:
# Incrementer.next ();;
- : int = 1
# Incrementer.next ();;
- : int = 2
# Incrementer.reset ();;
- : unit = ()
# Incrementer.next ();;
- : int = 1
# Incrementer.r;;
Error: Unbound value Incrementer.r
下面是一个更好的实现,允许您同时拥有多个Incrementers
。
module Incrementer : sig
type t
val create : unit -> t
val next : t -> int
val reset : t -> unit
end = struct
type t = int ref
let create () =
ref 0
let next t =
t := !t + 1;
!t
let reset t =
t := 0
end
让我们看看它的实际效果:
# let incrementer = Incrementer.create ();;
val incrementer : Incrementer.t = <abstr>
(* As you can see, the outer code never sees the `int ref` inside. *)
# Incrementer.next incrementer;;
- : int = 1
# Incrementer.next incrementer;;
- : int = 2
# Incrementer.reset incrementer;;
- : unit = ()
# Incrementer.next incrementer;;
- : int = 1
您还可以在单独的文件中编写签名和实现,以便单独编译它们。
答案 2 :(得分:0)
and
代替let
,in
仅用于本地上下文:
let r = ref 0
let fresh_var () = r := !r + 1 ; Var !r
and refresh () = r := 0
但是,由于您的函数不依赖于代码,因此此处不需要使用and
,因此您可以使用其他let
构造。
至于你的想法,你必须在一个单独的模块中定义这些函数,.mli
只声明它们而不是变量r
。
答案 3 :(得分:0)
OCaml还支持丰富的面向对象系统
class counter = object
val mutable r = 0
method value =
r
method incr =
r <- r + 1;
r
method reset =
r <- 0;
0
end
我们可以像这样使用counter
let () =
let c = new counter in
printf "counter value: %d\n" c#value; (* counter value: 0 *)
printf "counter value: %d\n" c#incr; (* counter value: 1 *)
printf "counter value: %d\n" c#incr; (* counter value: 2 *)
printf "counter value: %d\n" c#incr; (* counter value: 3 *)
printf "counter value: %d\n" c#value; (* counter value: 3 *)
printf "counter value: %d\n" c#value; (* counter value: 3 *)
printf "counter value: %d\n" c#reset; (* counter value: 0 *)
printf "counter value: %d\n" c#incr; (* counter value: 1 *)
类实例封装了他们的数据成员,因此我们可以轻松管理多个计数器
let () =
let a = new counter in
let b = new counter in
printf "A: %d, B: %d\n" a#value b#value; (* A: 0, B: 0 *)
printf "A: %d, B: %d\n" a#incr b#value; (* A: 1, B: 0 *)
printf "A: %d, B: %d\n" a#incr b#value; (* A: 2, B: 0 *)
printf "A: %d, B: %d\n" a#incr b#value; (* A: 3, B: 0 *)
printf "A: %d, B: %d\n" a#value b#incr; (* A: 3, B: 1 *)
printf "A: %d, B: %d\n" a#value b#incr; (* A: 3, B: 2 *)
printf "A: %d, B: %d\n" a#value b#incr; (* A: 3, B: 3 *)
printf "A: %d, B: %d\n" a#reset b#reset; (* A: 0, B: 0 *)