frpnow-0.18: Principled practical FRP

Control.FRPNow.Core

Description

Synopsis

# Pure interface

The FRPNow interface is centered around behaviors, values that change over time, and events, value that are known from some point in time on.

What the pure part of the FRPNow interface does is made precise by denotation semantics, i.e. mathematical meaning. The denotational semantics of the pure interface are

```type Event a = (Time+,a)

never :: Event a
never = (∞, undefined)

return x = (-∞,x)
(ta,a) >>= f = let (tb,b) = f a
in (max ta tb, b)

type Behavior a = Time -> a

return x = λt -> x
m >>= f  = λt -> f (m t) t

mfix f = λt -> let x = f x t in x

switch :: Behavior a -> Event (Behavior a) -> Behavior a
switch b (ts,s) = λn ->
if n < ts then b n else s n

whenJust :: Behavior (Maybe a) -> Behavior (Event a)
whenJust b = λt ->
let w = minSet { t' | t' >= t && isJust (b t') }
in  if w == ∞ then never
else (w, fromJust (b w))
```

Where `Time` is a set that is totally ordered set and has a least element, -∞. For events, we also use `Time+ = Time ∪ ∞`.

The notation `minSet x` indicates the minimum element of the set `x`, which is not valid Haskell, but is a valid denotation. Note that if there is no time at which the input behavior is `Just` in the present or future, then `minSet` will give the minimum element of the empty set, which is `∞`.

data Event a Source

An event is a value that is known from some point in time on.

Instances

 Source Source Source Plan b => Swap b Event Source

data Behavior a Source

An behavior is a value that changes over time.

A never occuring event

switch :: Behavior a -> Event (Behavior a) -> Behavior a Source

Introduce a change over time.

`b `switch` e `

Gives a behavior that acts as `b` initially, and switches to the behavior inside `e` as soon as `e` occurs.

whenJust :: Behavior (Maybe a) -> Behavior (Event a) Source

Observe a change over time.

The behavior `whenJust b` gives at any point in time the event that the behavior `b` is `Just` at that time or afterwards.

As an example,

```let getPos x
| x > 0 = Just x
| otherwise = Nothing
in whenJust (getPos <\$> b)```

Gives gives the event that the behavior `b` is positive. If `b` is currently positive then the event will occur now, otherwise it will be the first time that `b` becomes positive in the future. If `b` never again is positive then the result is `never`.

futuristic :: Behavior (Event a) -> Behavior (Event a) Source

Not typically needed, used for event streams.

If we have a behavior giving events, such that each time the behavior is sampled the obtained event is in the future, then this function ensures that we can use the event without inspecting it (i.e. before binding it).

If the implementation samples such an event and it turns out the event does actually occur at the time the behavior is sampled, an error is thrown.

# IO interface

data Now a Source

A monad that alows you to:

• Sample the current value of a behavior via `sampleNow`
• Interact with the outside world via `async`, `callback` and `sync`.
• Plan to do Now actions later, via `planNow`

All actions in the `Now` monad are conceptually instantaneous, which entails it is guaranteed that for any behavior `b` and Now action `m`:

```   do x <- sample b; m ; y <- sample b; return (x,y)
== do x <- sample b; m ; return (x,x)
```

Instances

 Source Source Source Source Source Source Source

async :: IO a -> Now (Event a) Source

Asynchronously execte an IO action, and obtain the event that it is done.

Starts a seperate thread for the IO action, and then immediatly returns the event that the IO action is done. Since all actions in the `Now` monad are instantaneous, the resulting event is guaranteed to occur in the future (not now).

Use this for IO actions which might take a long time, such as waiting for a network message, reading a large file, or expensive computations.

Note:Use this only when using FRPNow with Gloss or something else that does not block haskell threads. For use with GTK or other GUI libraries that do block Haskell threads, use `asyncOS` instead.

asyncOS :: IO a -> Now (Event a) Source

Like `async`, but uses an OS thread instead of a regular lightweight thread.

Useful when interacting with GUI systems that claim the main loop, such as GTK.

callback :: Now (Event a, a -> IO ()) Source

Create an event that occurs when the callback is called.

The callback can be safely called from any thread. An error occurs if the callback is called more than once.

See `callbackStream` for a callback that can be called repeatidly.

The event occurs strictly later than the time that the callback was created, even if the callback is called immediately.

sampleNow :: Behavior a -> Now a Source

Sample the present value of a behavior

planNow :: Event (Now a) -> Now (Event a) Source

Plan to execute a `Now` computation.

When given a event carrying a now computation, execute that now computation as soon as the event occurs. If the event has already occured when `planNow` is called, then the `Now` computation will be executed immediatly.

sync :: IO a -> Now a Source

Synchronously execte an IO action.

Use this is for IO actions which do not take a long time, such as opening a file or creating a widget.

# Entry point

runNowMaster :: Now (Event a) -> IO a Source

Run the FRP system in master mode.

Typically, you don't need this function, but instead use a function for whatever library you want to use FRPNow with such as `runNowGTK`, `runNowGloss`. This function can be used in case you are not interacting with any GUI library, only using FRPNow.

Runs the given `Now` computation and the plans it makes until the ending event (given by the inital `Now` computation) occurs. Returns the value of the ending event.

Arguments

 :: (IO (Maybe a) -> IO ()) An IO action that schedules some FRP actions to be run. The callee should ensure that all actions that are scheduled are ran on the same thread. If a scheduled action returns `Just x`, then the ending event has occured with value `x` and now more FRP actions are scheduled. -> Now (Event a) The `Now` computation to execute, resulting in the ending event, i.e. the event that stops the FRP system. -> IO ()

General interface to interact with the FRP system.

Typically, you don't need this function, but instead use a specialized function for whatever library you want to use FRPNow with such as `runNowGTK` or `runNowGloss`, which themselves are implemented using this function.