[Haskell-cafe] Arrow laws of Netwire

Ivan Perez ivanperezdominguez at gmail.com
Sun Feb 18 09:17:36 UTC 2018


> However, unless you have a strong reason to use arrowized FRP I would
recommend that you go with one of the first-class FRP libraries.

TL;DR: Shameless self promotion ahead: we built an elementary library that
seems to subsume many others, including AFRP and Classic FRP libraries, I'd
like to know how it compares.

Seeing what's just been said about netwire, I'd like to ask how these
compare to each other. Among themselves, and also in relation to a separate
construct that Manuel Bärenz and I built (note: I am the Yampa maintainer;
Yampa is alive and well and more updates are coming your way :) ).

In 2016 we published an article [1; mirror: 4] and a library [2] which aim
at merging ideas in this field. I always thought they were pretty powerful,
and so far I haven't found many limitations. (But I am biased, so maybe not
the ideal judge.)

It combines the CPS-based arrowized construct of Yampa with a monad, in a
tiny definition:

newtype MSF m a b = MSF { step :: a -> m (b, MSF m a b) }

So, you provide one input sample and get, in a monadic context, an output
and a continuation. Next time you provide the next input to the
continuation, and so on.

You can define stream as:

type MStream m b = MSF m () b

You can define sinks as:

type MSink m a = MSF m a ()

They have really cool properties [3], for instance, they are arrows, and if
the monad is commutative then the arrow is commutative. We have instances
for many other Arrow* classes.

You can also define FRP on top of it, in the time-continuous sense, by
using a Reader monad:

type YampaSF a b = MSF (Reader Time) a b

We have a version of Yampa defined on top of this that runs full (free and
commercial) games just fine. It's API compatible (for what it implements).

And, you can define classic FRP signals (and sinks, a-la reactive banana
and, if paired, more similar to Daniel Winograd-Cort's work or Keera Hails):

type Signal a = MStream Time a

So you can use applicative style:

s :: Signal Double
s = -- predefined somewhere

biggerS :: Signal Double
biggerS = (* 100) <*> s

You can do extremely cool things just by altering the monad:
- If the monad is Maybe, they terminate because there may not be a
continuation (and an output).
- If the monad is Either, they terminate with a result. This is the basis
for switching, which we get "for free".
- If the monad is [], they spawn. This implements parallelism with
broadcasting for free.
- You can use a Writer monad and some smart tricks to do continuous
collision detection.
- You can use state if to avoid the bottleneck issue that people criticise
AFRP for.
- You can use transformers to stack these effects.
- You can also use IO as your monad, if you want to access mouse position
and other external stuff, print a log, or sink directly from your network.

So far, I've found that we can pretty much do anything we want with this.
It's simple to use, classic or arrowized at will (you can combine the two).
I'm investigating performance, which for the games I've tried is really
good and gives us flat and low memory profiles, and I believe we can do
some pretty smart things with GADTS and re-writes to make things as fast as
they can theoretically be.

How does this compare to other FRP and F;RP libraries around?



PS. For whoever is interested, there's the FRP zoo on github that shows the
same example in multiple variants.

[1] https://dl.acm.org/citation.cfm?id=2976010
[2] https://hackage.haskell.org/package/dunai
[3] http://www.cs.nott.ac.uk/~psxip1/papers/msfmathprops.pdf

On 17 February 2018 at 11:43, Ertugrul Söylemez <esz at posteo.de> wrote:

> Hi,
> >         -- I almost sure this is correct, since it is copied
> >         -- from "Programming with Arrows", J. Hughes
> >       mapA :: (ArrowChoice a) => a b c -> a [b] [c]
> >       mapA f = proc input ->
> >         case input of
> >           [] -> returnA -< []
> >           z:zs -> do y_ <- f -< z
> >                      ys_ <- mapA f -< zs
> >                      returnA -< y_:ys_
> Yes, this is correct.  However, the ArrowChoice instance in Netwire has
> always been questionable.  The correct (and much more efficient) way to
> implement mapA is as a primitive combinator much like the parallel
> switches in Yampa.
> The Netwire implementation and API has been more focussed on providing
> features over reasonable semantics, and that eventually led me to
> abandon it in favour of a more minimalistic library that is easier to
> reason about (wires).  Please consider Netwire deprecated and I
> recommend you don't use it for new applications, if possible.  I'm still
> open to reviewing and merging code contributions to support legacy
> applications, but other than that I would much prefer to just let it
> become a piece of AFRP history. =)
> If you must use AFRP, I recommend either my new library called wires, or
> the progenitor of all, Yampa.  However, unless you have a strong reason
> to use arrowized FRP I would recommend that you go with one of the
> first-class FRP libraries.  I currently recommend either:
>   * reactive-banana: very simple and easy to learn API, plus the author
>     runs a blog with lots of information on FRP.  This is the library I
>     recommend to FRP beginners.  Or
>   * reflex: my personal favourite, more focussed on practical concerns
>     and efficiency, a more versatile API that easily integrates with
>     applications with a "main loop", such as real-time games.  The
>     trade-off is far less documentation and a more complicated API.
> Sorry for not directly addressing your question, but I hope I convinced
> you to just switch to a different library. =)
> Greets
> ertes
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180218/8748b00d/attachment.html>

More information about the Haskell-Cafe mailing list