OCaml:内部“让”两个函数

时间:2018-05-18 14:26:44

标签: ocaml let

我想内心“让”,但有两个功能。

我现在有一个功能

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中实现这个想法?

4 个答案:

答案 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代替letin仅用于本地上下文:

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 *)