caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* "Ref" and copy of functions
@ 2007-12-13 17:27 Pierre-Evariste Dagand
  2007-12-14 10:49 ` Zheng Li
  2007-12-16  5:17 ` [Caml-list] " Jacques Garrigue
  0 siblings, 2 replies; 14+ messages in thread
From: Pierre-Evariste Dagand @ 2007-12-13 17:27 UTC (permalink / raw)
  To: caml-list

Hi Caml-list,

I'm looking for advices about a "clean way" of doing something which,
by design, isn't. So, let states the problem.

I'm doing a combinator library based on Arrows for a Yampa-like system :

type ('a,'b) arrow = Arrow of ( 'a -> 'b )

Thus, I can instantiate an arrow with :

let arr f = Arrow ( f )
val arr : ('a -> 'b) -> ('a, 'b) arrow

Then, I have, for example, the composition of arrows :

let (>>>) (Arrow f) (Arrow g) =Arrow ( fun  c -> g  ( f  c ) )
val ( >>> ) : ('a, 'b) arrow -> ('b, 'c) arrow -> ('a, 'c) arrow

Right here, everything plays well (excepted some weak type variables
issues but that's not a big deal).

But (and that's here that the trouble is) I need a "loop" combinator,
that I wrote this way :

let loop init (Arrow f) =
  let state = ref init in
    Arrow (
      fun c ->
        let new_state , output = f ( !state , c ) in
          state := new_state;
          output
    )
val loop : 'a -> ('a * 'b, 'a * 'c) arrow -> ('b, 'c) arrow

Finally, I can write a small arrow  :

let arr_counter = loop 0 ( arr ( fun ( counter , x ) -> counter+1 ,
counter+x ) )
let arr_double = arr ( fun x -> 2*x )
let arr_my_small_arrow = arr_counter >>> arr_double

And I execute it with :

let run (Arrow f) input =
  f  input
val run : ('a, 'b) arrow -> 'a -> 'b

And it works. Right.

But now, I would like to be able to "copy" a built arrow and to be
able to execute the copy without side-effecting on the first one.
Obviously, I cannot do that in this implementation.

My current solution is really *ugly* :

let arrow_string = Marshal.to_string arrow [ Marshal.No_sharing ;
Marshal.Closures ]

Then I "Marshal.from_string arrow_string". I'm not even sure if it
will not blow out of my hands with "strange" things in the Ref cell.

I'm aware of implementations in CPS but I use to think that it has a
performance cost that I'm not ready to pay (I'm fighting against a C++
code so...).

So if someone knows an elegant solution to my problem (if someone has
read this mail until here), please let me know :-)


Best regards,



P.S.: For those who are just curious, these combinators are used in a
functional-reactive library for Peer-to-Peer overlays programming.

-- 
Pierre-Evariste DAGAND
http://perso.eleves.bretagne.ens-cachan.fr/~dagand/


^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: "Ref" and copy of functions
@ 2007-12-15 12:08 oleg
  2007-12-15 15:19 ` Pierre-Evariste Dagand
  0 siblings, 1 reply; 14+ messages in thread
From: oleg @ 2007-12-15 12:08 UTC (permalink / raw)
  To: pedagand, caml-list


If you like using the mutable state, perhaps you might find the
following code helpful. The key idea is packaging the clone function
along with the arrow. There is no longer any need in any unsafe
features. The lesson from our tagless final APLAS paper is that many
things are significantly easier if we do the work at the production
site rather than at the consumption site.

(* The first component is the arrow itself, the second one is the clone
   function*)
type ('a,'b) arrow = {arrow: 'a -> 'b; clone: unit -> ('a,'b) arrow};;

let rec arr f = {arrow = f; clone = fun () -> arr f};;

let rec (>>>) f g = {arrow = (fun c -> g.arrow (f.arrow c)); 
		     clone = (fun () -> f.clone () >>> g.clone ())};;

(* Here, our clone function uses the initial state rather than the
current state. It is trivial to clone from the current state, if
desired.*)

let rec loop init f =
  let state = ref init in
  {arrow =
      (fun c ->
        let new_state , output = f.arrow ( !state , c ) in
          state := new_state;
          output);
   clone = (fun () -> loop init (f.clone ()))};;

let arr_counter = loop 0 (arr (fun (counter, x) -> counter+1 ,counter+x));;
let arr_double = arr (fun x -> 2*x);;
let arr_my_small_arrow = arr_counter >>> arr_double;;

let run f input = let v1 = f.arrow input in
                  let v2 = f.arrow input in
		  (v1,v2);;


let test1 = run arr_my_small_arrow 10;;
  val test1 : int * int = (20, 22)

let test2 = run arr_my_small_arrow 10;;
  val test2 : int * int = (24, 26)  (*obviously, counter keeps
  counting *)

let test3 = run (arr_my_small_arrow.clone ()) 10;;
val test3 : int * int = (20, 22)  (* cloning `resets' the counter *)


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-12-16 18:27 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-12-13 17:27 "Ref" and copy of functions Pierre-Evariste Dagand
2007-12-14 10:49 ` Zheng Li
2007-12-14 14:51   ` [Caml-list] " David Teller
2007-12-14 16:19     ` Zheng Li
2007-12-14 14:54   ` [Caml-list] " Pierre-Evariste Dagand
2007-12-14 16:12     ` Zheng Li
2007-12-14 16:55       ` [Caml-list] " Pierre-Evariste Dagand
2007-12-14 16:30     ` Loup Vaillant
     [not found]       ` <6cb897b30712140848j52e5628avbf0e3dadcb771f71@mail.gmail.com>
2007-12-14 16:57         ` Pierre-Evariste Dagand
2007-12-16  5:17 ` [Caml-list] " Jacques Garrigue
2007-12-16 16:39   ` Pierre-Evariste Dagand
2007-12-16 18:27     ` Pierre-Evariste Dagand
2007-12-15 12:08 oleg
2007-12-15 15:19 ` Pierre-Evariste Dagand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).