Version française
Home     About     Download     Resources     Contact us    
Browse thread
Obj.magic and existential types.
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Guillaume Yziquel <guillaume.yziquel@c...>
Subject: Obj.magic and existential types.
Hello.

Please don't scream: I've been using Obj.magic...

But the result is rather interesting. It can record a flow of 
computations, and recompute them only when upstream data has been modified:

> # let (n', n) = Dependent.encapsulate 1;;
> val n' : int Dependent.data = <abstr>
> val n : int Dependent.t = <abstr>
> # let (_, next) = Dependent.encapsulate (fun x -> x + 1);;
> val next : (int -> int) Dependent.t = <abstr>
> # let m = Dependent.apply next n;;
> val m : int Dependent.t = <abstr>
> # Dependent.access m;;
> - : int = 2
> # Dependent.set n' 3;;
> - : unit = ()
> # Dependent.access m;;
> - : int = 4

The piece of code responsible for this behaviour is at the end of the 
message.

I learnt that I could perhaps overcome the use of Obj.magic by using 
existential types. I was advised to read the following post on this topic:

http://caml.inria.fr/pub/ml-archives/caml-list/2004/01/52732867110697f55650778d883ae5e9.en.html

However, I do not really understand how Daniel implemented existential 
types there, and I do not really see how it can be adapted to my code. 
Suggestions welcomed.

Here's the code, rather disorganised at the moment.

All the best,

Guillaume Yziquel.


> type read;;
> type write;;
> 
> type 'a computation = (Obj.t -> 'a) t * Obj.t t
> 
> and ('a, 'b) aux_t = Dependent of
>   ( 'a option ref *
>     'a computation option *
>     Obj.t t list ref)
> 
> and 'a data = ('a, write) aux_t
> and 'a t    = ('a, read)  aux_t;;
> 
> let encapsulate (x : 'a) : ('a data) * ('a t) =
>   let z = Dependent ((ref (Some x)), None, (ref [])) in (z, z);;
> 
> let add_dependency (alpha : 'a t) (beta : 'b t) =
>   let Dependent (_, _, dep) = alpha in
>   dep := ((Obj.magic beta) : Obj.t t)::!dep;;
> 
> let apply (f : ('b -> 'a) t) (x : 'b t) : 'a t =
>   let computation : 'a computation =
>     ((Obj.magic f) : (Obj.t -> 'a) t),
>     ((Obj.magic x) : Obj.t         t) in
>   let f_x : 'a t = Dependent (
>     ((ref None)         : 'a option ref),
>     ((Some computation) : 'a computation option),
>     ((ref [])           : Obj.t t list ref)) in
>   add_dependency f f_x;
>   add_dependency x f_x;
>   f_x;;
> 
> exception Undefined;;
> 
> module rec Aux :
> sig
> 
>   val access : 'a t -> 'a
>   val update : 'a t -> ('b -> 'a) t -> 'b t -> 'a
>   val reset  : 'a t -> unit
> 
> end = struct
> 
>   let rec access y =
>     let Dependent (opt_ref_x, comp_opt, _) = y in
>     match !opt_ref_x with | Some x -> x | None ->
>     begin match comp_opt with
>       | None -> raise Undefined
>       | Some (fun_t, arg_t) -> Aux.update y fun_t arg_t
>     end
> 
>   and update y fun_t arg_t =
>     let Dependent (opt_ref_x, _, dependencies) = y in
>     List.iter Aux.reset !dependencies;
>     let result = (Aux.access fun_t) (Aux.access arg_t) in
>     opt_ref_x := Some result; result
> 
>   and reset z =
>     let Dependent (opt_ref_x, _, dependencies) = z in
>     match !opt_ref_x with
>     | None -> () | Some _ -> begin
>         opt_ref_x := None;
>         List.iter Aux.reset !dependencies
>     end;;
> 
> end;;
> 
> include Aux;;
> 
> exception Flawed_implementation;;
> 
> let set (x : 'a data) (v : 'a) : unit =
>   let Dependent (opt_ref_x, comp_opt, dependencies) = x in
>   match comp_opt with | Some _ -> raise Flawed_implementation | None ->
>   begin List.iter Aux.reset !dependencies;
>         opt_ref_x := Some v
>   end;;

-- 
      Guillaume Yziquel
http://yziquel.homelinux.org/