Reputation: 153
I want to make inner "let", but for two functions.
I have now a function
let fresh_var () =
let r = ref 0 in
r := !r + 1 ; Var !r;;
I want to add second function so that it could change r, but r stays invisible for the rest of the program. Something like:
let r = ref 0 in
let fresh_var () = r := !r + 1 ; Var !r
and let refresh () = r := 0
But piece above doesn't work because of syntax error.
How can I implement this idea in OCaml?
Upvotes: 2
Views: 1649
Reputation: 135406
OCaml also supports a rich object-oriented system
class counter = object
val mutable r = 0
method value =
r
method incr =
r <- r + 1;
r
method reset =
r <- 0;
0
end
We can use our counter
like this
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 *)
Class instances encapsulate their data members, so we can easily manage multiple counters
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 *)
Upvotes: 0
Reputation: 953
You can simply create one function returning a pair of functions:
let get_fresh_and_reset () =
let r = ref 0 in
(fun () -> incr r; !r), (fun () -> r := 0)
let fresh, reset = get_fresh_and_reset ()
Also note that the correct syntax is :=
and not =:
.
Edit:
As @Virgile mentioned, in case if you don't need several counters you can simplify:
let fresh_var, refresh =
let r = ref 0 in (fun () -> incr r; !r), (fun () -> r:=0)
Upvotes: 3
Reputation: 2959
This is not how things work in OCaml. Local definitions are exactly that, local. They cannot be shared between functions.
If you want to abstract part of your implementation, I suggest using modules instead.
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
See it in action below:
# Incrementer.next ();;
- : int = 1
# Incrementer.next ();;
- : int = 2
# Incrementer.reset ();;
- : unit = ()
# Incrementer.next ();;
- : int = 1
# Incrementer.r;;
Error: Unbound value Incrementer.r
Below is a better implementation which allows you to have multiple Incrementers
at once.
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's see it in action:
# 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
You can also write the signature and the implementation in separate files in order to compile them separately.
Upvotes: 2
Reputation: 727
and
is used instead of let
when you want to write joint declarations, and in
is only used in local contexts:
let r = ref 0
let fresh_var () = r := !r + 1 ; Var !r
and refresh () = r := 0
However, since your functions are not codependent the use of and
is not necessary here so you could use another let
construct.
As for the idea you have, you would have to define these functions in a seperate module whose .mli
only declares them and not the variable r
.
Upvotes: 0