[Haskell-cafe] Arrow laws of Netwire

Ertugrul Söylemez esz at posteo.de
Mon Feb 19 08:31:51 UTC 2018


> I suspect I may not be understanding precisely what you mean. Perhaps
> you can describe this in more detail or with an example?

The easiest way to see the difference is by looking at some of the
combinators.  Notice that things like 'hold', 'scan'/'accum', and 'tag'
are real functions.  In a first-class FRP system these would have types
like the following:

    hold :: a -> Event a -> Moment (Behaviour a)
    scan :: a -> Event (a -> a) -> Moment (Event a)
    tag  :: Behaviour (a -> b) -> Event a -> Event b

The Moment monad is not inherent to the way the underlying state machine
is constructed, but acts merely as a provider for the notion of "now".
Since 'tag' doesn't need that notion, it's a completely pure function.
You can have that function in AFRP as well:

    fmap :: (a -> b) -> Event a -> Event b

However, unlike 'fmap', 'tag' makes sense in a pure context.  You can
pass an Event and a Behaviour to a different thread via an MVar, combine
them there, then send the result back, and it will still work in the
context of the greater application (no isolated state machines).  You
can hold an event in any concurrent thread, etc.

Another example is that if the underlying monad is nontrivial (say IO)
you can't easily split behaviours in a pure context in AFRP.  This
restriction does not exist in first-class FRP:

    unzipB :: Behavior (a, b) -> (Behavior a, Behavior b)
    splitE :: Event (Either a b) -> (Event a, Event b)

In AFRP you always have to do it in the context of the underlying state
machine, i.e. MSF/SF/Wire, which means that AFRP forces you to manage
all data structures holding reactive values as part of it or, again,
have isolated state machines.  With first-class FRP there is nothing
wrong with keeping a data structure of behaviours in an MVar and have
two concurrent threads modify it:

    MVar (Map K (Behaviour String))

AFRP requires the following instead, and unless all changes are planned
within the state machine and communicated via 'A' changes actually build
up in terms of complexity (you can't just keep composing it with more
and more MSF actions for free):

    MVar (MSF IO A (Map K String))

Let me make clear that you can express all of these things in AFRP.  In
fact it's easily more powerful than first-class FRP, because if the
system exposes it, you get full access to the expressivity of what is
basically a generic state machine.  Just to provide one example: there
is no first-class counterpart to 'manage' from wires, because that
combinator only really makes sense in the context of the underlying
state machine.  But all of this comes at the expense of giving up
first-class behaviours and events in the above sense.

If this still doesn't convince you, I strongly suggest that you give
reflex a try.  It has a very similar controller interface to AFRP
(stepWire/unMSF) in that it gives you control over the main loop, so it
shouldn't feel too alien.

As a final remark due to all these issues and more with AFRP most of my
research in the past few years went into getting rid of the A while
retaining most of its advantages.  Reflex (by Ryan Trinkle, not me) is
almost there: it has the performance, the predictability and the
expressivity.  The only missing component is an equivalent to 'manage',
i.e. effects without the controller round-trip, or what I call
"switching with effects".


Greets
ertes
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: not available
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180219/af990e2e/attachment.sig>


More information about the Haskell-Cafe mailing list