Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: Netwire fromRational (Ertugrul S?ylemez)
2. Re: FRP (Heinrich Apfelmus)
3. Re: FRP (Ertugrul S?ylemez)
4. Re: Netwire fromRational (Nathan H?sken)
5. Re: Netwire fromRational (Chadda? Fouch?)
6. Re: Netwire fromRational (Nathan H?sken)
----------------------------------------------------------------------
Message: 1
Date: Wed, 3 Oct 2012 14:04:41 +0200
From: Ertugrul S?ylemez <[email protected]>
Subject: Re: [Haskell-beginners] Netwire fromRational
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="utf-8"
Nathan H?sken <[email protected]> wrote:
> I noticed than when using this code:
>
> (-1.0) . isKeyPressed leftKeyCode <|> 0.0
>
> instead of
>
> (pure (-1.0)) . isKeyPressed leftKeyCode <|> (pure 0.0)
>
> than "fromRational" gets called. I am wondering, if this is not pretty
> inefficient.
No, it's the same thing. When you write 'pure 1.0', then you're using,
say, Double's Fractional instance directly. If you write just '1.0',
then you're using Wire's Fractional instance, which is just defined as:
fromRational = pure . fromRational
So it's the same thing.
> I am noticing this, because when I compile a netwire test program with
> haste, the first code segment fails during runtime because of the
> primOp newByteArray#.
Michael Snoyman has reported that Netwire 4 compiled fine using GHCJS.
Give that one a try.
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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20121003/dbe9ac66/attachment-0001.pgp>
------------------------------
Message: 2
Date: Wed, 03 Oct 2012 15:07:40 +0200
From: Heinrich Apfelmus <[email protected]>
Subject: Re: [Haskell-beginners] FRP
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=UTF-8; format=flowed
Thanks for the explanation!
So, netwire is essentially based on the abstraction
type Stoplight red green = Behavior' (Either red green)
of time-varying values that can either be a "normal" value of type
green , or an "exceptional" ("inhibiting") value of type red . (I have
dropped the input dependence, so that arrow composition becomes normal
function application.)
Here, Behavior' denotes a type of continues time-varying values, with
the small twist that it can "detect some flanks", namely when the value
jumps from Right to Left . In this way, the flank can be interpreted
as an Event in the reactive-banana sense.
The applicative instance is the composition of the applicative instances
for Behavior' and Either
instance Monoid red => Applicative (Stoplight red) where
pure x = pure (Right x)
f <*> x = (<$)> <$> f <*> x
if we assume that Either has the following applicative instance
instance Monoid red => Applicative (Either red) where
pure = Right
(Right x) <*> (Right y) = Right (x y)
(Left x) <*> (Right y) = Left x
(Right x) <*> (Left y) = Left y
(Left x) <*> (Left y) = Left (x <*> y)
What I particularly like about this approach is the following: I like to
think of Behavior as continuous functions, not necessarily because they
are really continuous, but because this means that the semantics of
Behavior is independent of any "update frequency", which is key point in
simplifying code with FRP. Unfortunately, this means that we cannot
"detect flanks", because a continuously changing Behavior simply does
not change in discrete steps.
The Stoplight type solves this problem by introducing an explicit "this
is a flank" value, i.e. by using the fact that the only way an Either
type can change is in discrete steps. Due to parametricity, I can't put
this information into the general Behavior type, but the special case
Behavior (Either red green) can make use of this.
On the other hand, while the combination of Behaviors and Events allows
for some slick switching combinators, I'm not entirely sure whether the
mixture of two unrelated concepts (continuous functions vs singular
occurrences) is too much of a conceptual burden.
Best regards,
Heinrich Apfelmus
Ertugrul S?ylemez wrote:
> Heinrich Apfelmus 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.
--
http://apfelmus.nfshost.com
------------------------------
Message: 3
Date: Wed, 3 Oct 2012 16:12:45 +0200
From: Ertugrul S?ylemez <[email protected]>
Subject: Re: [Haskell-beginners] FRP
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
Heinrich Apfelmus <[email protected]> wrote:
> So, netwire is essentially based on the abstraction
>
> type Stoplight red green = Behavior' (Either red green)
>
> of time-varying values that can either be a "normal" value of type
> green , or an "exceptional" ("inhibiting") value of type red . (I have
> dropped the input dependence, so that arrow composition becomes normal
> function application.)
>
> Here, Behavior' denotes a type of continues time-varying values, with
> the small twist that it can "detect some flanks", namely when the
> value jumps from Right to Left . In this way, the flank can be
> interpreted as an Event in the reactive-banana sense.
This is not really how it works. Inhibition causes the rest of the wire
to inhibit, in other words:
_ . empty = empty
> The applicative instance is the composition of the applicative
> instances for Behavior' and Either
>
> instance Monoid red => Applicative (Stoplight red) where
> pure x = pure (Right x)
> f <*> x = (<$)> <$> f <*> x
>
> if we assume that Either has the following applicative instance
>
> instance Monoid red => Applicative (Either red) where
> pure = Right
> (Right x) <*> (Right y) = Right (x y)
> (Left x) <*> (Right y) = Left x
> (Right x) <*> (Left y) = Left y
> (Left x) <*> (Left y) = Left (x <*> y)
In particular the above means that with (<*>) when the function wire
inhibits, the application itself inhibits:
empty <*> _ = empty
The Monoid constraint is on the Alternative class instead, where
selection happens. The reason why it has to be a monoid is for the
Alternative laws to hold.
> What I particularly like about this approach is the following: I like
> to think of Behavior as continuous functions, not necessarily because
> they are really continuous, but because this means that the semantics
> of Behavior is independent of any "update frequency", which is key
> point in simplifying code with FRP. Unfortunately, this means that we
> cannot "detect flanks", because a continuously changing Behavior
> simply does not change in discrete steps.
>
> The Stoplight type solves this problem by introducing an explicit
> "this is a flank" value, i.e. by using the fact that the only way an
> Either type can change is in discrete steps. Due to parametricity, I
> can't put this information into the general Behavior type, but the
> special case Behavior (Either red green) can make use of this.
Netwire doesn't do everything to hide the discrete nature of stepping,
but this isn't really a conceptual choice, but rather the simple fact
that I provide predefined wires that expose this (for example in
Control.Wire.Prefab.Accum). If you use only time-continuous wires, then
the perception is the same as in a continuous model, probably even more
so as handling events becomes simple algebra instead of explicit
switching:
"yes" . holdFor 1 (periodically 2) <|> "no"
The reason is that Netwire is developed with flexibility in mind. In
fact the original motivation was to enable development of reactive
networking applications, where time or continuity isn't much of a
concern. I wanted to be able to express such systems declaratively
without giving up the ability to reason easily about how it will behave
at runtime.
There is an experimental web framework based on Netwire 1 called
Webwire, and I'm planning to revive it, because FRP makes developing web
applications (server side!) really convenient, especially when you have
to handle forms or other interactive things.
> On the other hand, while the combination of Behaviors and Events
> allows for some slick switching combinators, I'm not entirely sure
> whether the mixture of two unrelated concepts (continuous functions vs
> singular occurrences) is too much of a conceptual burden.
The wire concept is at least equivalent to the classic events/behaviors
split, because you can translate both behaviors and events to wires.
You will find that most event signal functions from Yampa are also
present in Netwire, except that they are potentially inhibiting wires
instead of event signals.
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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20121003/2c92cfb5/attachment-0001.pgp>
------------------------------
Message: 4
Date: Wed, 03 Oct 2012 18:12:13 +0200
From: Nathan H?sken <[email protected]>
Subject: Re: [Haskell-beginners] Netwire fromRational
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
On 10/03/2012 02:04 PM, Ertugrul S?ylemez wrote:
> When you write 'pure 1.0', then you're using,
> say, Double's Fractional instance directly. If you write just '1.0',
> then you're using Wire's Fractional instance, which is just defined as:
>
> fromRational = pure . fromRational
>
> So it's the same thing.
Let me simplify the example:
testW1 :: WireP () Double
testW1 = pure 1.0
testW2 :: WireP () Double
testW2 = 1.0
main = do
let (res, _) = stepWire 1.0 () testW
putStrLn $ show res
(set testW to testW1 or testW2).
When I test this with testW=testW2 I see that "fromRational" is called
which converts a Rational (=Ration Integer) to a WireP () Double (I
tested this by adding a "trace" to the fromRational
Control/Wire/Classes.hs).
This means the "1.0" is converted to a Rational and then back to a WireP
() Double, correct?
> Michael Snoyman has reported that Netwire 4 compiled fine using GHCJS.
> Give that one a try.
I currently can not get ghcjs to work, but I will continue trying.
Regards,
Nathan
------------------------------
Message: 5
Date: Wed, 3 Oct 2012 22:18:03 +0200
From: Chadda? Fouch? <[email protected]>
Subject: Re: [Haskell-beginners] Netwire fromRational
To: Nathan H?sken <[email protected]>
Cc: [email protected]
Message-ID:
<canfjzra7svculjctycfu3uylqtu082jfdxh3ig7e2995rsy...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
On Wed, Oct 3, 2012 at 6:12 PM, Nathan H?sken <[email protected]> wrote:
> On 10/03/2012 02:04 PM, Ertugrul S?ylemez wrote:
>> When you write 'pure 1.0', then you're using,
>> say, Double's Fractional instance directly. If you write just '1.0',
>> then you're using Wire's Fractional instance, which is just defined as:
>>
>> fromRational = pure . fromRational
>>
>> So it's the same thing.
>
> Let me simplify the example:
>
> testW1 :: WireP () Double
> testW1 = pure 1.0
>
> testW2 :: WireP () Double
> testW2 = 1.0
>
> main = do
> let (res, _) = stepWire 1.0 () testW
> putStrLn $ show res
>
> (set testW to testW1 or testW2).
> When I test this with testW=testW2 I see that "fromRational" is called
> which converts a Rational (=Ration Integer) to a WireP () Double (I
> tested this by adding a "trace" to the fromRational
> Control/Wire/Classes.hs).
> This means the "1.0" is converted to a Rational and then back to a WireP
> () Double, correct?
1.0 _is_ a Rational in the first place, it's a number literal that is
not integral, so it is translated to a fraction (Rational) by the
parser then converted at runtime (only once so no worry about
efficiency) to the proper type in the Fractional type class by
fromRational, like Double, Float, Ratio, ... Here it's a WireP ()
Double.
This is how this code works :
> let
> x :: (Fractional a) => a
> x = 1.23
> y = (3.5 :: Double) + x
> z = (2.7 :: Float) + x
Note : Does GHC optimize the case were the final type is monomorphic
and standard (Double, Float) if -O2 is given ? Sure one fromRational
by literal shouldn't hurt much but...
--
Jeda?
------------------------------
Message: 6
Date: Wed, 03 Oct 2012 23:13:38 +0200
From: Nathan H?sken <[email protected]>
Subject: Re: [Haskell-beginners] Netwire fromRational
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=UTF-8
On 10/03/2012 10:18 PM, Chadda? Fouch? wrote:
> 1.0 _is_ a Rational in the first place, it's a number literal that is
> not integral, so it is translated to a fraction (Rational) by the
> parser then converted at runtime (only once so no worry about
> efficiency) to the proper type in the Fractional type class by
> fromRational, like Double, Float, Ratio, ... Here it's a WireP ()
> Double.
>
> This is how this code works :
>
>> let
>> x :: (Fractional a) => a
>> x = 1.23
>> y = (3.5 :: Double) + x
>> z = (2.7 :: Float) + x
>
That is good to know. I was unaware that 1.0 is parsed as a rational.
Thanks for the explanation.
> Note : Does GHC optimize the case were the final type is monomorphic
> and standard (Double, Float) if -O2 is given ? Sure one fromRational
> by literal shouldn't hurt much but...
I could argue that it also increased the size of the compiled
executable, but I am guessing it is of little magnitude.
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 52, Issue 4
****************************************