Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Caml-list] Recursion on React.events.

16 views
Skip to first unread message

Guillaume Yziquel

unread,
Dec 8, 2009, 9:40:50 PM12/8/09
to OCaml List, Daniel Bünzli
Hello.

I've been dabbling with recursive definition of React events.

Suppose I have a function called schedule of type

val schedule : Calendar.t -> unit React.event

which throws out an event at the specified time or date.

I've been trying to create a regular_schedule function that throws
events at a regular pace. Daniel Bünzli's module is great, but sometimes
a bit rough to get by, specifically on examples such as this one.

So I came up with a recursive definition of such a React.event:

> let rec regular_schedule start_time period =
> React.E.switch React.E.never begin React.E.map
> begin fun () -> regular_schedule (Calendar.add (Calendar.now ()) period) period end
> begin schedule start_time end
> end

First question:

It almost works, in the sense that if you insert a print_endline after
the fun (), well, it indeeds prints stuff on stdin at the specified
pace. However, somehow, the event as a whole behaves as React.E.never.
So it doesn't work. I guess it has to do with the way React.switch works
synchronously, but I really do not get it.

Second question:

Is there somehow a notion of 'tail recursion' for such constructs?

All the best,

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

_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

Guillaume Yziquel

unread,
Dec 8, 2009, 10:23:42 PM12/8/09
to OCaml List, Daniel Bünzli
Guillaume Yziquel a écrit :

> Hello.
>
> I've been dabbling with recursive definition of React events.
>
> Suppose I have a function called schedule of type
>
> val schedule : Calendar.t -> unit React.event
>
> which throws out an event at the specified time or date.
>
> I've been trying to create a regular_schedule function that throws
> events at a regular pace. Daniel Bünzli's module is great, but sometimes
> a bit rough to get by, specifically on examples such as this one.
>
> So I came up with a recursive definition of such a React.event:
>
>> let rec regular_schedule start_time period =
>> React.E.switch React.E.never begin React.E.map
>> begin fun () -> regular_schedule (Calendar.add (Calendar.now ())
>> period) period end
>> begin schedule start_time end
>> end
>
> First question:
>
> It almost works, in the sense that if you insert a print_endline after
> the fun (), well, it indeeds prints stuff on stdin at the specified
> pace. However, somehow, the event as a whole behaves as React.E.never.
> So it doesn't work. I guess it has to do with the way React.switch works
> synchronously, but I really do not get it.

OK. The following piece of code works out, but it seems to me that using
a React.E.select in this position is a rather ugly hack.

let rec regular_schedule start period =
let waiting_for = schedule start in
React.E.switch React.E.never begin React.E.map
begin fun () -> React.E.select [waiting_for; regular_schedule


(Calendar.add (Calendar.now ()) period) period]

end waiting_for
end


> Second question:
>
> Is there somehow a notion of 'tail recursion' for such constructs?

I gave some thought to it, and it seems quite plausible that what is
done in the first place is analoguous to tail recursion. And that using
React.E.select breaks the tail recursion. Am I offtrack?

Daniel Bünzli

unread,
Dec 8, 2009, 11:25:28 PM12/8/09
to guillaum...@citycable.ch, caml...@inria.fr
>> let rec regular_schedule start_time period =
>>  React.E.switch React.E.never begin React.E.map
>>    begin fun () -> regular_schedule (Calendar.add (Calendar.now ())
>> period) period end
>>    begin schedule start_time end
>>  end

Look at the semantic definition of E.switch in the documentation. When
a tick happens the whole switch switches instantaneously to the event
for the new tick returned by regular_schedule which will happen in
now+period. You never see ticks because as soon a tick happen you
replace the event that should "show" the tick by "showing" the next
tick.

Anyway don't do any recursive tricks unless you really know what you
are doing (which you don't seem). You are asking for trouble (infinite
loops and puzzling behaviour more precisely). The ONLY right way to
define recursive events and signals is to use the fixed point
operators. So in your case something like this should work :

let regular_schedule start_time period =
let define tick = (* tick is the value of tick' dt times ago *)
let tick' =
let reschedule () = Calendar.add (Calendar.now ()) period in
React.E.switch (schedule start_time) (E.map reschedule tick)
in
tick', tick'
in
E.fix define

So basically after a tick' happens, tick will immediatly (but not
instantaneously) happen and reschedule a new tick' occurence.

Note that in general I would avoid what you are doing altoghether by
providing regular_schedule as a primitive as you do for schedule. If
you are using too much ugly side effects and tricks in your event
definitions then you loose all the benefits of frp.

Best,

Daniel

P.S. You may want to have a look at rtime : http://erratique.ch/software/rtime

Daniel Bünzli

unread,
Dec 9, 2009, 2:53:46 AM12/9/09
to guillaum...@citycable.ch, OCaml List
> Daniel Bünzli's module is great, but sometimes a bit rough
> to get by, specifically on examples such as this one.

I would just like to point out that this has nothing to do with the
module per se but understanding frp in general and this is the reason
why I went to great length to document the semantics for each of the
combinators I provide --- something most frp libraries won't bother to
do, leaving you with testing or looking into the implementation for
understanding things when tricky simulateneity issues arise.

Thus to understand why your event didn't work you could have done the
following. Provided you understand the notations given here :

http://erratique.ch/software/react/doc/React#sem


1) Define a semantics for your primitive events and functions.

[Calendar.schedule st]_t = Some () iff t = st
[Calendar.now ()]_t = t


2) Reason on your expression, by applying the semantics of the
combinators and your primitives.

Let's try to look what happens at st for (regular_schedule st p)
assuming p > 0.

[regular_schedule st p]_st =
[E.switch E.never ee]_st
with ee = E.map (fun () -> regular_schedule ...) (schedule st)

Since we have [schedule st]_st = Some (), by the semantics of E.map we
have [ee]_st = Some ev. Thus we are in the second case of the semantics
of E.switch (see doc) and the semantics of the switch reduces to the
semantics of ev, i.e.

[E.switch E.never ee]_st =
[regular_schedule (Calendar.add (Calendar.now ()) p) p]_st =
[E.switch E.never ee']_st
with ee' = E.map (fun () -> regular_schedule ..) (schedule (st + p))

Now by the semantics of schedule and E.map you know nothing will
happen on ee' before st + p ans since p > 0 we are in the first case
of the semantics of E.switch and the last switch reduces to the
semantics of E.never. To sum up :

[regular_schedule st p]_st = [E.never]_st = None

So at st, nothing happens, as you witnessed. Applying the same
technique you could generalize the result for any t.

Pure equational reasoning, it's not that hard, or is it ?

Best,

Daniel

P.S. In my previous email

let reschedule () = Calendar.add (Calendar.now ()) period

should read

let reschedule () = schedule (Calendar.add (Calendar.now ()) period)

I misunderstood the type of Calendar.add.

Richard Jones

unread,
Dec 9, 2009, 6:23:29 AM12/9/09
to Daniel Bünzli, OCaml List
On Wed, Dec 09, 2009 at 03:53:36PM +0800, Daniel B�nzli wrote:
> > Daniel B�nzli's module is great, but sometimes a bit rough

> > to get by, specifically on examples such as this one.
>
> I would just like to point out that this has nothing to do with the
> module per se but understanding frp in general [...]

Personally I've yet to read any comprehensible introduction to FRP.
I'm interested in whether FRP can be used to write Gtk interfaces with
reduced code complexity. Apparently it can, but I've no idea how.

Rich.

--
Richard Jones
Red Hat

Guillaume Yziquel

unread,
Dec 9, 2009, 1:00:59 PM12/9/09
to Richard Jones, Daniel Bünzli, OCaml List
Richard Jones a écrit :
> On Wed, Dec 09, 2009 at 03:53:36PM +0800, Daniel Bünzli wrote:
>>> Daniel Bünzli's module is great, but sometimes a bit rough

>>> to get by, specifically on examples such as this one.
>> I would just like to point out that this has nothing to do with the
>> module per se but understanding frp in general [...]
>
> Personally I've yet to read any comprehensible introduction to FRP.
> I'm interested in whether FRP can be used to write Gtk interfaces with
> reduced code complexity. Apparently it can, but I've no idea how.
>
> Rich.

Concerning documentation, Daniel's documentation is pretty good, and
it's all that's been necessary to get me going. You should try having a
look at it.

I have little experience with Gtk, but I've written an Eliom web
application using the ExtJS framework for windowing in browsers. In some
sense, it's more complex than a Gtk application, because you have to
manage lots of users, sessions, et ceteræ.

Moreover the Eliom module was keeping track of the state of an Asterisk
server, and initiating phone calls.

I must say that using React was the only way to write the application
cleanly and in a minimum amount of time.

I was basically using signals for:

-1- proxying persistent information such as user data and configuration
in the SQLite database

-2- parsing the output of the text-based Asterisk Manager Interface

-3- keeping track of the state of the Asterisk server, and interacting
with it (making phone calls, when the phone hangs up, when a call could
not be made, etc...)

-4- Keeping track of the IP of users of the web application coming from
Ocsigen, and reconciliation with the IP of the softphones as registered
by Asterisk (this allowed to avoid using passwords on the LAN)

-5- Keeping track of the history of the phone calls made by agent, and
feed it back to the administrator's web session

-6- Doing all the "real-time" AJAX interaction for updating tables,
windowing, et ceteræ.

Doing it in a FRP way allowed to focus on the semantics, and moreover
React update cycles integrate nicely with Lwt as used by Ocsigen. So you
can do really cool stuff with it. It took me roughly one and half to two
weeks from scratch (including learning the ExtJS library,
troubleshooting the Asterisk Manager Interface, et ceteræ), with quite a
lot of other concurrent obligations to handle.

So yes, FRP is really cool.

Unfortunately, it seems to me that Daniel's module is fairly low-level
in the sense that it implements the bare mechanics and semantics of FRP.
For real world application, you have to be quite nifty with tricky
details about update cycles. For example, make a parser of the Asterisk
Manager Interface with React around OCamlNet's Uq_engine module proved
to be quite tricky, in a similar way as the issue that started this
thread (here, I had no event, but in the Asterisk parser, I had doubled
events, and I solved it in a very very ugly way).

It's true that I may not completely understand how React works, as
Daniel stated it before (a bit better now), but, for instance, the
React.E.switch or React.S.switch is something that you'll be using a
lot. And I feel the need for higher-level functions to deal with it,
even though I do not have yet a precise idea of which such functions.

All the best,

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

_______________________________________________

Guillaume Yziquel

unread,
Dec 9, 2009, 1:24:39 PM12/9/09
to Daniel Bünzli, OCaml List
Daniel Bünzli a écrit :

>> Daniel Bünzli's module is great, but sometimes a bit rough
>> to get by, specifically on examples such as this one.
>
> I would just like to point out that this has nothing to do with the
> module per se but understanding frp in general and this is the reason
> why I went to great length to document the semantics for each of the
> combinators I provide --- something most frp libraries won't bother to
> do, leaving you with testing or looking into the implementation for
> understanding things when tricky simulateneity issues arise.

I appreciate the documentation effort you put up. Really.

> Thus to understand why your event didn't work you could have done the
> following. Provided you understand the notations given here :
>
> http://erratique.ch/software/react/doc/React#sem

I do. I've done quite a lot of maths after all, and this doesn't
frighten me.

> Since we have [schedule st]_st = Some (), by the semantics of E.map we
> have [ee]_st = Some ev. Thus we are in the second case of the semantics
> of E.switch (see doc) and the semantics of the switch reduces to the
> semantics of ev, i.e.

Maybe I was looking in the wrong place, but I haven't found "the second
case of the semantics of E.switch" on your website. In fact, the way I
learned about React.E.switch was from the .mli-style webpage on your
website, and by trial and error.

> Pure equational reasoning, it's not that hard, or is it ?

Less than semi-algebraic geometry.

More seriously, the point was not understanding why it failed. I came to
the same conclusions from empirical evidence. The point was how to
overcome it.

And while I do not doubt that your documentation is rather explicit, I
was nevertheless confused by your fixed point operators, and thus rather
reluctant to use them.

The example on your website:

> let history ?(eq = ( = )) s =
> let push v = function
> | [] -> [ v ]
> | v' :: _ as l when eq v v' -> l
> | l -> v :: l
> in
> let define h =
> let h' = S.l2 push s h in
> h', h'
> in
> S.fix [] define

One thing that really troubles me, is that I do not understand why
define returns a couple of two identical element. And the typing of
E.fix is rather confusing:

> val fix : ('a React.event -> 'a React.event * 'b) -> 'b

Why do we return a 'b type with E.fix?

While the webpage mentions this dependence on the value at t-dt, it's
quite hard to infer from the use of the fix point operator in the
example how it's really supposed to behave and to be called.

Clarifying these issues would be welcome.

All the best,

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

_______________________________________________

Guillaume Yziquel

unread,
Dec 9, 2009, 1:47:53 PM12/9/09
to Daniel Bünzli, caml...@inria.fr
Daniel Bünzli a écrit :

>>> let rec regular_schedule start_time period =
>>> React.E.switch React.E.never begin React.E.map
>>> begin fun () -> regular_schedule (Calendar.add (Calendar.now ())
>>> period) period end
>>> begin schedule start_time end
>>> end
>
> Anyway don't do any recursive tricks unless you really know what you
> are doing (which you don't seem). You are asking for trouble (infinite
> loops and puzzling behaviour more precisely). The ONLY right way to
> define recursive events and signals is to use the fixed point
> operators. So in your case something like this should work :
>
> let regular_schedule start_time period =
> let define tick = (* tick is the value of tick' dt times ago *)
> let tick' =
> let reschedule () = Calendar.add (Calendar.now ()) period in
> React.E.switch (schedule start_time) (E.map reschedule tick)
> in
> tick', tick'
> in
> E.fix define

Thanks. This works perfectly! (I mean, with the tweak you mentioned in
your second email).

I still do not understand why there's the couple (tick', tick') and not
simply tick', nevertheless...

> Note that in general I would avoid what you are doing altoghether by
> providing regular_schedule as a primitive as you do for schedule. If
> you are using too much ugly side effects and tricks in your event
> definitions then you loose all the benefits of frp.

Well, I do not fully agree. While I agree that keeping code clear and
non-confusing is the best option, I do not really know if I can avoiding
doing such magic.

My use case is the following: I'm writing a scheduler that I hope to
extend smartly over time. It's a scheduler that is based on Calendar,
and that runs in a Lwt.thread. Source code is given below, at the end of
this email. There's a schedule function that somehow registers a task in
the scheduler, and returns a React.E.event on which code using the
library can hook to.

Making a regular_schedule in the way you suggested proved to be quite
difficult without changing the code of the scheduler itself, which I'd
like to keep clean and small.

Moreover, I also aim to make a auto_schedule function that does some
rescheduling at with a delay that is know at the time of rescheduling.

Generally speaking, I want to keep the scheduler small and clean, and
give flexibility to the user of the scheduling library. So providing
regular_schedule as a primitive does not seem to me to fit this perspective.

> Best,
>
> Daniel
>
> P.S. You may want to have a look at rtime : http://erratique.ch/software/rtime

Cool. One criticism and one question.

Criticism: it doesn't use Calendar, which really a cool library.

Question: How well does Rtime interact with Lwt?

I'll have a look at what I can do with it.

Here's the code of the scheduler:

> open Lwt
> open CalendarLib
>
> type task = {
> schedule : Calendar.t;
> trigger : unit -> unit; }
>
> let compare t1 t2 =
> let n = Calendar.Date.compare
> (Calendar.to_date t1.schedule)
> (Calendar.to_date t2.schedule) in
> if n = 0 then CalendarLib.Calendar.Time.compare
> (Calendar.to_time t1.schedule)
> (Calendar.to_time t2.schedule)
> else n
>
> let tasks : task list ref = ref []
>
> let register_new_task t =
> let rec aux = function | [] -> t::[] | hd::tl ->
> begin match compare hd t with
> | 1 -> t::hd::tl | _ -> hd::(aux tl) end
> in tasks := aux !tasks
>
> let (read_control_fd, write_control_fd) = Lwt_unix.pipe ()
>
> let task_channel = ref None
> let task_mutex = Lwt_mutex.create ()
>
> let _ =
> let rec receive_order = let buffer_command = " " in begin fun () ->
> match Unix.read (Lwt_unix.unix_file_descr read_control_fd) buffer_command 0 1 with
> | 1 -> begin match !task_channel with
> | Some new_task -> begin
> task_channel := None;
> Lwt_mutex.unlock task_mutex;
> register_new_task new_task;
> loop () end
> | None -> assert false
> end
> | _ -> assert false end
> and loop () : unit Lwt.t = match !tasks with
> | [] -> Lwt_unix.wait_read read_control_fd >>= fun () -> receive_order ()
> | hd::tl -> let float_delay =
> Calendar.Time.Second.to_float (
> Calendar.Time.Period.to_seconds (
> Calendar.Period.to_time (
> Calendar.sub hd.schedule (
> Calendar.now ())))) in
> begin match float_delay > 0. with
> | false -> tasks := tl; hd.trigger (); loop ()
> | true -> Lwt.catch begin fun () ->
> Lwt_unix.with_timeout float_delay begin function () ->
> Lwt_unix.wait_read read_control_fd >>= fun () ->
> receive_order () end
> end begin function
> | Lwt_unix.Timeout -> tasks := tl; hd.trigger (); loop ()
> | _ -> assert false
> end end in
> loop ()
>
> let schedule date =
> let aux () =
> let (e, set_e) = React.E.create () in
> Lwt_mutex.lock task_mutex >>= fun () ->
> task_channel := Some {schedule = date; trigger = set_e;};
> Lwt_unix.write write_control_fd "X" 0 1 >>= function
> | 1 -> Lwt.return e | _ -> assert false in
> Lwt_main.run (aux ())
>
> let regular_schedule start period =
> (* The let define tick in E.fix define is the proper way to
> implement recursive events. define has type React.event ->
> (React.event * React.event) and its argument is a placeholder
> for the event at time t-dt. *)
> let define tick =
> let tick' = React.E.switch (schedule start) (React.E.map begin function () ->
> schedule (Calendar.add (Calendar.now ()) period) end tick) in
> tick', tick'
> in
> React.E.fix define

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

_______________________________________________

Daniel Bünzli

unread,
Dec 10, 2009, 2:21:19 AM12/10/09
to guillaum...@citycable.ch, OCaml List, Richard Jones
> Unfortunately, it seems to me that Daniel's module is fairly low-level in
> the sense that it implements the bare mechanics and semantics of FRP.

Yes, react is low-level and will remain. The rationale is that I want
the client of the module to be able to decide the application
structure. This makes react more flexible and easier to embed were you
need to.

I could have decided that react has a global queue and every primitive
update has to go through that queue (for the client this would have
simplified the feedback of primitives into the reactive system). But
then the module is not thread-safe and you get compositional problems
when you want to integrate two libraries
using react in a threaded environment. I could have decided that the
reactive engine runs on its own thread but maybe you don't want to use
threads etc.

For example with the current design two part of a program may use
react as they wish internally without any problem even on different
threads as long as their signals and events don't interact. With the
current structure it also means that a library designer using react
has to make sure the way he design should play nice with other part
defining their own primitive events.

So yes it means a little bit more work and understanding for the
client. But I think it pays to have a reactive engine that doesn't
impose too much on you. The client always knows better the abstraction
he's after and the setting in which it has to implement it. But if a
consistent and compositional pattern of use emerges I'm always willing
to support it directly in the library.

> For example, make a parser of the Asterisk Manager Interface
> with React around OCamlNet's Uq_engine module proved to be quite tricky, in
> a similar way as the issue that started this thread (here, I had no event,
> but in the Asterisk parser, I had doubled events, and I solved it in a very
> very ugly way).

Note that as we discussed I highly suspect you used the wrong
abstraction there (events vs. signals).

> It's true that I may not completely understand how React works, as Daniel stated it before (a bit better now)

Btw this was not intended to be offensive. It was to say the reactive
engine has a well defined way to work that should be respected (the
update cycle) so don't try to trick around too much with it when you
cannot achieve want you want.

Best,

Daniel

Daniel Bünzli

unread,
Dec 10, 2009, 3:24:47 AM12/10/09
to guillaum...@citycable.ch, OCaml List
> Maybe I was looking in the wrong place, but I haven't found "the second case
> of the semantics of E.switch" on your website. In fact, the way I learned
> about React.E.switch was from the .mli-style webpage on your website, and by
> trial and error.

Here :

http://erratique.ch/software/react/doc/React.E.html#VALswitch

Second bullet.

> One thing that really troubles me, is that I do not understand why define
> returns a couple of two identical element. And the typing of E.fix is rather
> confusing:
>
>> val fix : ('a React.event -> 'a React.event * 'b) -> 'b

Yes it's confusing. It's here to allow to define mutually recursive
definitions and still expose them to the outside world. It is also
usefull if you have other values that depend on the delayed value and
you want to expose them to the outside world. There are example of
this in the breakout.ml example.

[snip] I tried to rexeplain E.fix and S.fix but I came up with what's
written in their documentation sorry.

Daniel

Daniel Bünzli

unread,
Dec 10, 2009, 3:39:38 AM12/10/09
to guillaum...@citycable.ch, caml...@inria.fr
> I still do not understand why there's the couple (tick', tick') and not
> simply tick', nevertheless...

The tick' on the left is the event you are delaying (i.e. the one you
will receive as an argument to defining function but delayed). The
tick' on the right is what you want to get out from the defining
function, here both are equal but that may not be always the case.

>
>> Note that in general I would avoid what you are doing altoghether by
>> providing regular_schedule as a primitive as you do for schedule. If
>> you are using too much ugly side effects and tricks in your event
>> definitions then you loose all the benefits of frp.
>
> Well, I do not fully agree.

In fact I retract my comment in that case. I thought you were playing
dirty tricks but in fact you were not. Sorry.

> Cool. One criticism and one question.
>
> Criticism: it doesn't use Calendar, which really a cool library.

I don't think you need Calendar to provide what rtime provides.

> Question: How well does Rtime interact with Lwt?

No idea I have never used Lwt.

Daniel

Guillaume Yziquel

unread,
Dec 10, 2009, 4:41:08 PM12/10/09
to Daniel Bünzli, OCaml List
Daniel Bünzli a écrit :

>> Maybe I was looking in the wrong place, but I haven't found "the second case
>> of the semantics of E.switch" on your website. In fact, the way I learned
>> about React.E.switch was from the .mli-style webpage on your website, and by
>> trial and error.
>
> Here :
>
> http://erratique.ch/software/react/doc/React.E.html#VALswitch
>
> Second bullet.

I think you should really make a direct link to this page from either

http://erratique.ch/software/react/doc/React.html

or

http://erratique.ch/software/react/doc/index.html

because I've been on your website quite a few times, and it's the first
time I see this page. (Which is really useful).

>> One thing that really troubles me, is that I do not understand why define
>> returns a couple of two identical element. And the typing of E.fix is rather
>> confusing:
>>
>>> val fix : ('a React.event -> 'a React.event * 'b) -> 'b
>
> Yes it's confusing. It's here to allow to define mutually recursive
> definitions and still expose them to the outside world. It is also
> usefull if you have other values that depend on the delayed value and
> you want to expose them to the outside world. There are example of
> this in the breakout.ml example.
>
> [snip] I tried to rexeplain E.fix and S.fix but I came up with what's
> written in their documentation sorry.
>
> Daniel

Same comment for E.fix as for E.switch. I have never seen its
documentation before. It's much much clearer now.

All the best,

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

_______________________________________________

Guillaume Yziquel

unread,
Dec 10, 2009, 5:24:03 PM12/10/09
to Daniel Bünzli, OCaml List, Richard Jones
Daniel Bünzli a écrit :

>> Unfortunately, it seems to me that Daniel's module is fairly low-level in
>> the sense that it implements the bare mechanics and semantics of FRP.
>
> Yes, react is low-level and will remain. The rationale is that I want
> the client of the module to be able to decide the application
> structure. This makes react more flexible and easier to embed were you
> need to.

That's perfect. You should perhaps think of creating a Convenience
submodule where some useful patterns could be thrown in by third
parties. After having been 'moderated' by you, of course.

> I could have decided that react has a global queue and every primitive
> update has to go through that queue (for the client this would have
> simplified the feedback of primitives into the reactive system). But
> then the module is not thread-safe and you get compositional problems
> when you want to integrate two libraries
> using react in a threaded environment. I could have decided that the
> reactive engine runs on its own thread but maybe you don't want to use
> threads etc.

No no no! Indeed, it's much better as it is today.

> For example with the current design two part of a program may use
> react as they wish internally without any problem even on different
> threads as long as their signals and events don't interact. With the
> current structure it also means that a library designer using react
> has to make sure the way he design should play nice with other part
> defining their own primitive events.

Yes, indeed. But that's also the tricky part where some useful
constructs would indeed be... useful.

> So yes it means a little bit more work and understanding for the
> client. But I think it pays to have a reactive engine that doesn't
> impose too much on you. The client always knows better the abstraction
> he's after and the setting in which it has to implement it. But if a
> consistent and compositional pattern of use emerges I'm always willing
> to support it directly in the library.

All to true. But that would be the purpose of a Convenience submodule
(once you get constructive feedback).

>> For example, make a parser of the Asterisk Manager Interface
>> with React around OCamlNet's Uq_engine module proved to be quite tricky, in
>> a similar way as the issue that started this thread (here, I had no event,
>> but in the Asterisk parser, I had doubled events, and I solved it in a very
>> very ugly way).
>
> Note that as we discussed I highly suspect you used the wrong
> abstraction there (events vs. signals).

Very possibly. I will have to get back to it one day to make it clean.
Now that I know where to find the documentation for E.fix, it's only a
question of *cough* time *cough*.

>> It's true that I may not completely understand how React works, as Daniel stated it before (a bit better now)
>
> Btw this was not intended to be offensive. It was to say the reactive
> engine has a well defined way to work that should be respected (the
> update cycle) so don't try to trick around too much with it when you
> cannot achieve want you want.

Yes. It's also here where I worry about a few things concerning Lwt:

In Lwt, you have a monadic way to do context switches for multithreading
withing a single real thread. So if you use Lwt inside the update cycle,
you could well jump out of the update cycle with a Lwt context switch.
As long as you do not encounter a Lwt construct within definition of
signals and events, you can be pretty sure that the update cycle will go
through to its end without using Lwt inside an event/signal. But at the
same time, it seems that the monadic way Lwt is built avoids us such
problems. But I may be mistaken.

This issue can be interesting and important.

'a Lwt.t represents the type of a promise of something of type 'a,
essentially. So you could use in parallel processing: Imagine that 'a
Remote.t represents the type of something computed on a remote computer.
You could use type 'a Remote.t Lwt.t to represent the promise of a
computation of 'a done on a remote computer. It therefore could make
sense to have a single computer in charge of receiving React.events with
a unique update cycle, and transfering the computation to other
computers, represented as non-primary 'a Remote.t Lwt.t React.signal-s.
Using S.fix, one could also feed events to such a signal, using S.fix to
bind the t-dt Lwt.t value of the signal to the t value of the same signal.

That may seem quite involved, but conceptually, it could be a clean way
to type rather efficiently parallel computations. When binding such
signals, you could also implement code mobility, marshaling features to
take care of the work load of multiple computers.

So the compatibility of Lwt and React seems to me a worthwile question
if one wants to use OCaml for high availability, reactive, parallel
computations. And in this context, making E/S.switch easy to use would
quite important...

> Best,
>
> Daniel

All the best,

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

_______________________________________________

Daniel Bünzli

unread,
Dec 10, 2009, 8:22:26 PM12/10/09
to guillaum...@citycable.ch, OCaml List
> I think you should really make a direct link to this page from either

Well, there's one thing I cannot do for you is to learn to browse.
There are at least 11 direct links to these pages from React.html,
without counting the two direct module definition links which I
thought you would have clicked at some point.

Now I'm very impressed you went that far ignoring all this documentation.

About Lwt, I'm open to any suggestion to make react easier to interact
with (however at the moment I don't want react to depend on Lwt). Lwt
is also something I want to get into at some point but now is not the
time. I saw some kind of support was added to Lwt for react. If the
authors of Lwt are on this list, maybe they want to comment on what
their vision is.

Best,

Daniel

Jérémie Dimino

unread,
Dec 11, 2009, 7:16:49 AM12/11/09
to guillaum...@citycable.ch, OCaml List
Le jeudi 10 décembre 2009 à 23:24 +0100, Guillaume Yziquel a écrit :
> Yes. It's also here where I worry about a few things concerning Lwt:
>
> In Lwt, you have a monadic way to do context switches for multithreading
> withing a single real thread. So if you use Lwt inside the update cycle,
> you could well jump out of the update cycle with a Lwt context switch.
> As long as you do not encounter a Lwt construct within definition of
> signals and events, you can be pretty sure that the update cycle will go
> through to its end without using Lwt inside an event/signal. But at the
> same time, it seems that the monadic way Lwt is built avoids us such
> problems. But I may be mistaken.

It is possible to use Lwt inside an update cycle. It is not a problem to
switch context in an update cycle as long as you respect React's rules.

> So the compatibility of Lwt and React seems to me a worthwile question
> if one wants to use OCaml for high availability, reactive, parallel
> computations. And in this context, making E/S.switch easy to use would
> quite important...

Thanks to React being lowlevel, the two libraries are compatible out of
the box.

Jérémie

0 new messages