Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] static variables in a function
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: John Prevost <j.prevost@c...>
Subject: Re: [Caml-list] static variables in a function
>>>>> "mk" == Max Kirillov <max630@mail.ru> writes:

    mk> Oh, thank you for clarification. I'm very new to functional
    mk> programming, and didn't know yet about tricks like this. As I
    mk> understand, the point was to call 'ref' at initialization
    mk> stage. I thought about using 'lazy' for that, but still placed
    mk> it inside a full function definition, so it didn't help.

    mk> This makes a possibility to write very funny functions. For
    mk> example:

# let acc v =
    let vR = ref v in
    fun f -> 
            let newV = f !vR in
          vR := newV;
          newV  ;;

    mk> I'm not sure if this style of coding better than placing the
    mk> mutable values to be hidden inside modules or classes. Even
    mk> when possible (in other languages), I prefer to use latter way
    mk> to do. Well it's a matter of taste.

It also depends precisely what you're trying to do.  In the case we
first saw (we have a specific function that wants to have an input
buffer, essentially), I'm not sure it makes a great amount of sense.
The problem is that using a variable in the closure doesn't help do
anything except hide the value from the rest of the module.  And,
well, we'd probably be better off leaving it open to the module and
using the module interface to hide it from other modules.

If we change our focus, howeverm the technique becomes more
interesting.  Take a look at this, for example:

type 'a memoval =
  | Val of 'a
  | Exn of exn

let memoize f =
  let stow = Hashtbl.create 20 in
  fun x -> begin
    if not (Hashtbl.mem stow x) then begin
      try (let v = f x in Hashtbl.replace stow x (Val v))
        with e -> Hashtbl.replace stow x (Exn e)
     end;
    match Hashtbl.find stow x with
      | Val x -> x
      | Exn e -> raise e
  end

(* this is the fibonacci sequence, but we delaying "binding" the
   recursion until later. *)
let fib' fib' =
  function
    | 0 -> 1
    | 1 -> 1
    | n -> fib' (n-1) + fib' (n-2);;

(* example of how to bind the recursion in a simple way *)
let rec fib_r1 x =
  fib' fib_r1 x

(* and now binding it "through" the memoize function *)
let rec fib_r2 x =
  memoize (fib' fib_r2) x

In this case, the whole point of the function is that it produces a
function identical in every way to the original function, except that
it memoizes its work so as not to repeat.  There's no convenient
"object" to stuff the value into, because the function *is* our
object.  The only way we can store the data correctly is to have the
information somehow attached to the function we're creating.

There are a number of places where this is useful.  The key insight is
that in a functional language, the primary objects in the system are
functions, and this mechanism we're using above is simply what happens
when a variable goes out of scope for everything except the function
in question.

JOhn.
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners