Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do some of threepenny-gui FRP combinators operate on a MonadIO monad instead of being pure?

First of all a disclaimer, I might have misunderstood completely the way threepenny-gui works due to my not so advanced knowledge of Haskell, so take my assertions with a grain of salt. :-)

It seems to me that some combinators are not pure e.g.

stepper :: MonadIO m => a -> Event a -> m (Behavior a)

Is stepper necessarily operating on some type of IO monad (and it's therefore not pure), or I'm I misunderstanding something here ? Second question, if those combinators are indeed unpure, why is that ? To me this makes the code for building the event graph much less nice then reactive-banana since one has to use an IO monad instead of being just pure plain functions. The code seems to just become more complicated then in reactive-banana.

Even more scary, valueChange appears to be pure from the type

valueChange :: Element -> Event String

but it's actually using unsafeMapIO inside, so is it actually doing hidden IO ? Again, I might be misunderstanding something, but isn't this the most supreme sin in Haskell ? It was also confusing, I couldn't tell from type how the call-back registration was happening... this never happened to me before in Haskell... Was this done to spare users having to deal with the Frameworks monad ?

like image 353
miguel.negrao Avatar asked Apr 13 '14 15:04

miguel.negrao


2 Answers

I'm not a threepenny-gui user, but I can give you a bit of info on your questions from my reading of the code.

Firstly regarding stepper: It seems that internally threpenny-gui uses IORefs to keep track of accumulating parameters. That's why stepper requires MonadIO. However, I do not think this requires IO to build your event graph, it just means it has to run in IO. This shouldn't cause any awkwardness for you as an API user. If you think it does please post a more specific question.

Secondly regarding valueChange being implemented in terms of an unsafe function: Yes, this is very common to see in Haskell libraries. Haskell library authors often use unsafe functions when they know the way that they are used is actually safe for all possible execution paths, but it is not possible to prove this to the type system. In other words, library authors use unsafe operations in a safe way so that you don't have to!

like image 188
Tom Ellis Avatar answered Nov 07 '22 11:11

Tom Ellis


This answer is complementary to Tom Ellis'. It covers how I would justify the monadic FRP combinators from the perspective of a Threepenny user.

With Threepenny, odds are that a large part of your event graph will be built from Elements, which live in UI (a thin wrapper for IO) because they are tied to a DOM in a browser. That being so, it makes sense to remove the indirection involved in externally plugging something like reactive-banana (as the old reactive-banana-threepenny package used to do). In the case of reactive-banana-threepenny the indirection was not limited to having to use the Frameworks monad, but it also involved converting between the different event types of reactive-banana and Threepenny (it is also worth considering that FRP in Threepenny is optional; you can also use events in a traditional, imperative fashion).

Overall, it is a trade-off: to eliminate some indirection and make the API more immediately accessible, some cleanliness in defining the event graphs is sacrificed. In my experience, however, the trade-off is worth it.

On a closing note, this discussion I had with Heinrich around the time of the switch away from reactive-banana-threepenny may shed some more light on the matter.

like image 24
duplode Avatar answered Nov 07 '22 12:11

duplode