[Haskell-beginners] FRP

Kim-Ee Yeoh ky3 at atamo.com
Fri Sep 21 07:06:44 CEST 2012


Move to haskell-cafe you two.

(j/k -- I think the discussion is great here. If you also cc'ed -cafe, your
points would get higher visibility.)


-- Kim-Ee


On Fri, Sep 21, 2012 at 8:53 AM, Ertugrul Söylemez <es at ertes.de> wrote:

> Heinrich Apfelmus <apfelmus at quantentunnel.de> wrote:
>
> > > Wire is also an Alternative, which allows concise and efficient
> > > switching with very little cruft.  The following wire renders "yes"
> > > when the "keyDown Space" event happens and "no" otherwise:
> > >
> > >     pure "yes" . keyDown Space <|> pure "no"
> > >
> > > Or with the OverloadedStrings extension:
> > >
> > >     "yes" . keyDown Space <|> "no"
> > >
> > > All classic (non-wire) FRP implementations need switching or another
> > > ad-hoc combinator for this.  If you happen to need switching it's
> > > also a lot simpler using wires:
> > >
> > >     "please press space" . notE (keyDown Space) --> "thanks"
> > >
> > > This one waits for the Space key and then outputs "thanks" forever.
> > > So far Netwire has the fastest and most elegant way of dealing with
> > > events compared to all other libraries I have tried.
> >
> > These examples look neat!
> >
> > I'm a bit confused about the model you are using, though. If I
> > understand that correctly, you don't distinguish between events and
> > behaviors; rather, you are working with data streams in discrete time
> > steps. Still, I don't quite understand.
>
> First let me try to put reactive-banana's model into a data type of my
> own, which you might call TimedZipStream.  The name Behavior is easier,
> so let me pick that one instead (Time is the type for time deltas):
>
>     newtype Behavior a =
>         Behavior {
>           stepBehavior :: Time -> Network (a, Behavior a)
>         }
>
> This is not anywhere near how reactive-banana represents its behaviors,
> but just a simplified and less powerful model.  The argument is the time
> delta to the last instant.  Communication happens through the Network
> monad and is opaque to the user.  The type is an applicative functor
> that represents values that can behave differently at each instant.
>
> My model is similar to Yampas model, where instead of time-varying
> values you have time-varying functions, so-called signal functions:
>
>     newtype SF a b =
>         SF {
>           stepSF :: Time -> a -> (b, SF a b)
>         }
>
> This is a function from an 'a' to a 'b' that mutates over time.  There
> is a counterpart for classic behaviors, which is when the input type is
> fully polymorphic:
>
>     time :: SF a Time
>
> SF forms a family of applicative functors, but now there is a direct
> path from one signal function to the next, because SF is itself a
> category.  No graph, no monad, just plain categorical composition.
> Unfortunately to this day Yampa does not provide an Applicative
> instance, so you have to use the Arrow interface, which is usually very
> ugly.
>
> The weak spot of both models is events.  They need to be handled using
> switchers and other combinators.  Causality, simultaneity and choice all
> need to be encoded explicitly.  Event modifiers work outside of the
> behavior level.
>
> What makes Netwire different?  Wire categories are encoded by the
> following (simplified) type:
>
>     newtype Wire e a b =
>         Wire {
>           stepWire :: Time -> a -> (Either e b, Wire e a b)
>         }
>
> Wires can choose not to output anything, but instead inhibit with a
> value of type 'e'.  Where i is an inhibiting wire the following
> identities hold:
>
>     x . i = i
>     i . x = i
>
> Furthermore now when 'e' is a Monoid Wire is a family of Alternative
> functors with the following identities, where x and y produce and i, j
> and ij' and inhibit:
>
>     x <|> y = x
>     i <|> y = y
>
>     i <|> j = ij'
>
> The ij' wire also inhibits, but mappend-combines the inhibition values.
> The empty wire always inhibits with mempty.  The monoid is necessary for
> the Category, Applicative and Alternative laws to hold.
>
>
> > What is
> >
> >      pure "yes" . keyDown Space <|> pure "no"
> >
> > supposed to mean? If it's a function Time -> String , how long does it
> > have the "yes" value? 439.7 milliseconds? If it's an event, how often
> > does the "no" event fire?
>
> An event wire is a wire that acts like the identity wire when it
> produces, but may choose to inhibit instead:
>
>     pure "yes" . keyDown Space
>
> The 'keyDown Space' wire acts like the identity wire when the space key
> is pressed, otherwise it inhibits.  As a consequence of the above laws
> the composition also inhibits.  This is where (<|>) comes in:
>
>     pure "yes" . keyDown Space <|> pure "no"
>
> When the left wire inhibits, the right wire takes over.  By definition a
> 'pure' wire never inhibits.  Notice that in this example I'm assuming
> that 'keyDown' is a 'continuous event'.  That's where behaviors are
> mixed with events.  An event can actually have a duration.
>
> If 'keyDown' would be instantaneous without a duration you could use the
> 'holdFor' combinator:
>
>     pure "yes" . holdFor 1 (keyDown Space) <|> pure "no"
>
> This would also work for a continuous 'keyDown' event wire.  Then if you
> press the space key for one second, "yes" is displayed for two seconds.
>
>
> > Concerning the other example, I don't understand what the expression
> >
> >     "please press space" . notE (keyDown Space)
> >
> > means. If it's a function, what value does it have when the key was
> > pressed? If it's an event, how often does it "fire" the string value?
>
> In this case it doesn't really matter if 'keyDown Space' has a duration
> or not.  As soon as it produces once, the switch happens and the next
> wire takes over.  There is another name for the (-->) combinator called
> 'andThen'.
>
>     x --> y
>
> As soon as x inhibits, this combination switches to y.
>
> Side note:  Unlike classic FRP a wire category is not time-bound.  In
> fact in the current official release of Netwire (3.1.0) time is actually
> an extension.  In Netwire time is back as a primitive, because it makes
> time-related wires (the analog to behaviors) much easier to write.  I
> have retained the flexibility that your wire can have a time frame
> different from real time, though.
>
>
> Greets,
> Ertugrul
>
> --
> Not to be or to be and (not to be or to be and (not to be or to be and
> (not to be or to be and ... that is the list monad.
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20120921/219ed670/attachment.htm>


More information about the Beginners mailing list