<div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>Hi<br><br>> 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. <br><br></div><div>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.<br><br></div><div>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 :) ).<br></div><div><br></div>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.)<br><br>It combines the CPS-based arrowized construct of Yampa with a monad, in a tiny definition:<br><br></div>newtype MSF m a b = MSF { step :: a -> m (b, MSF m a b) }<br><br></div><div>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.<br></div><div><br></div>You can define stream as:<br><br></div>type MStream m b = MSF m () b<br><br></div>You can define sinks as:<br><br></div>type MSink m a = MSF m a ()<br><br></div>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.<br><br></div>You can also define FRP on top of it, in the time-continuous sense, by using a Reader monad:<br><br></div>type YampaSF a b = MSF (Reader Time) a b<br><br></div><div>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).<br></div><div><br></div>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):<br><br></div>type Signal a = MStream Time a<br><br></div>So you can use applicative style:<br><br></div>s :: Signal Double<br></div><div>s = -- predefined somewhere<br><br></div>biggerS :: Signal Double<br></div>biggerS = (* 100) <*> s<br><br></div><div>You can do extremely cool things just by altering the monad:<br>- If the monad is Maybe, they terminate because there may not be a continuation (and an output).<br>- If the monad is Either, they terminate with a result. This is the basis for switching, which we get "for free".<br></div><div>- If the monad is [], they spawn. This implements parallelism with broadcasting for free.<br></div><div>- You can use a Writer monad and some smart tricks to do continuous collision detection.<br></div><div>- You can use state if to avoid the bottleneck issue that people criticise AFRP for.<br></div><div>- You can use transformers to stack these effects.<br></div><div>- 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.<br><br></div><div>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.<br><br></div><div>How does this compare to other FRP and F;RP libraries around?<br><br></div><div>Cheers<br><br></div><div>Ivan<br><br></div><div>PS. For whoever is interested, there's the FRP zoo on github that shows the same example in multiple variants.<br><br>[1] <a href="https://dl.acm.org/citation.cfm?id=2976010">https://dl.acm.org/citation.cfm?id=2976010</a><br></div><div><div>[2] <a href="https://hackage.haskell.org/package/dunai">https://hackage.haskell.org/package/dunai</a><br></div><div>[3] <a href="http://www.cs.nott.ac.uk/~psxip1/papers/msfmathprops.pdf">http://www.cs.nott.ac.uk/~psxip1/papers/msfmathprops.pdf</a><br>[4] <a href="http://www.cs.nott.ac.uk/~psxip1/papers/2016-HaskellSymposium-Perez-Barenz-Nilsson-FRPRefactored-short.pdf">http://www.cs.nott.ac.uk/~psxip1/papers/2016-HaskellSymposium-Perez-Barenz-Nilsson-FRPRefactored-short.pdf</a><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On 17 February 2018 at 11:43, Ertugrul Söylemez <span dir="ltr"><<a href="mailto:esz@posteo.de" target="_blank">esz@posteo.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<span class=""><br>
>         -- I almost sure this is correct, since it is copied<br>
>         -- from "Programming with Arrows", J. Hughes<br>
>       mapA :: (ArrowChoice a) => a b c -> a [b] [c]<br>
>       mapA f = proc input -><br>
>         case input of<br>
>           [] -> returnA -< []<br>
>           z:zs -> do y_ <- f -< z<br>
>                      ys_ <- mapA f -< zs<br>
>                      returnA -< y_:ys_<br>
<br>
</span>Yes, this is correct.  However, the ArrowChoice instance in Netwire has<br>
always been questionable.  The correct (and much more efficient) way to<br>
implement mapA is as a primitive combinator much like the parallel<br>
switches in Yampa.<br>
<br>
The Netwire implementation and API has been more focussed on providing<br>
features over reasonable semantics, and that eventually led me to<br>
abandon it in favour of a more minimalistic library that is easier to<br>
reason about (wires).  Please consider Netwire deprecated and I<br>
recommend you don't use it for new applications, if possible.  I'm still<br>
open to reviewing and merging code contributions to support legacy<br>
applications, but other than that I would much prefer to just let it<br>
become a piece of AFRP history. =)<br>
<br>
If you must use AFRP, I recommend either my new library called wires, or<br>
the progenitor of all, Yampa.  However, unless you have a strong reason<br>
to use arrowized FRP I would recommend that you go with one of the<br>
first-class FRP libraries.  I currently recommend either:<br>
<br>
  * reactive-banana: very simple and easy to learn API, plus the author<br>
    runs a blog with lots of information on FRP.  This is the library I<br>
    recommend to FRP beginners.  Or<br>
<br>
  * reflex: my personal favourite, more focussed on practical concerns<br>
    and efficiency, a more versatile API that easily integrates with<br>
    applications with a "main loop", such as real-time games.  The<br>
    trade-off is far less documentation and a more complicated API.<br>
<br>
Sorry for not directly addressing your question, but I hope I convinced<br>
you to just switch to a different library. =)<br>
<br>
<br>
Greets<br>
ertes<br>
<br>______________________________<wbr>_________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/haskell-<wbr>cafe</a><br>
Only members subscribed via the mailman list are allowed to post.<br></blockquote></div><br></div>