varying-0.7.1.0: FRP through value streams and monadic splines.

Copyright(c) 2015 Schell Scivally
LicenseMIT
MaintainerSchell Scivally <schell@takt.com>
Safe HaskellNone
LanguageHaskell2010

Control.Varying.Core

Contents

Description

Varying values represent values that change over a given domain.

A varying value takes some input as its domain (e.g. time, place, etc) and when run using runVarT it produces a value and a new varying value. This pattern is known as an automaton and varying uses this pattern at its core. With the additon of monadic event sequencing, varying makes it easy to construct complicated signals that control program and data flow.

Synopsis

Types and Typeclasses

type Var a b = VarT Identity a b Source #

A var parameterized with Identity that takes input of type a and gives output of type b. This is the pure, effect-free version of VarT.

newtype VarT m a b Source #

A continuously varying value, with effects. It's a kind of Mealy machine (an automaton).

Constructors

VarT

Run a VarT computation with an input value of type a, yielding a step - a value of type b and a new computation for yielding the next step.

Fields

Instances
Monad m => Arrow (VarT m) Source #

Vars are arrows, which means you can use proc notation, among other meanings.

>>> :set -XArrows
>>> :{
let v = proc t -> do
          x <- accumulate (+) 0 -< t
          y <- accumulate (+) 1 -< t
          returnA -< x + y
in testVarOver v [1,1,1]
>>> :}
3
5
7

which is equivalent to

>>> let v = (+) <$> accumulate (+) 0 <*> accumulate (+) 1
>>> testVarOver v [1,1,1]
3
5
7
Instance details

Defined in Control.Varying.Core

Methods

arr :: (b -> c) -> VarT m b c #

first :: VarT m b c -> VarT m (b, d) (c, d) #

second :: VarT m b c -> VarT m (d, b) (d, c) #

(***) :: VarT m b c -> VarT m b' c' -> VarT m (b, b') (c, c') #

(&&&) :: VarT m b c -> VarT m b c' -> VarT m b (c, c') #

MonadPlus m => ArrowZero (VarT m) Source # 
Instance details

Defined in Control.Varying.Core

Methods

zeroArrow :: VarT m b c #

MonadPlus m => ArrowPlus (VarT m) Source # 
Instance details

Defined in Control.Varying.Core

Methods

(<+>) :: VarT m b c -> VarT m b c -> VarT m b c #

Monad m => ArrowChoice (VarT m) Source # 
Instance details

Defined in Control.Varying.Core

Methods

left :: VarT m b c -> VarT m (Either b d) (Either c d) #

right :: VarT m b c -> VarT m (Either d b) (Either d c) #

(+++) :: VarT m b c -> VarT m b' c' -> VarT m (Either b b') (Either c c') #

(|||) :: VarT m b d -> VarT m c d -> VarT m (Either b c) d #

Monad m => ArrowApply (VarT m) Source # 
Instance details

Defined in Control.Varying.Core

Methods

app :: VarT m (VarT m b c, b) c #

MonadFix m => ArrowLoop (VarT m) Source # 
Instance details

Defined in Control.Varying.Core

Methods

loop :: VarT m (b, d) (c, d) -> VarT m b c #

Monad m => Category (VarT m :: * -> * -> *) Source #

A var is a category. id = var id f . g = g >>> f

or

 f . g = f <<< g
>>> let v = accumulate (+) 0 . 1
>>> testVarOver v [(),(),()]
1
2
3
Instance details

Defined in Control.Varying.Core

Methods

id :: VarT m a a #

(.) :: VarT m b c -> VarT m a b -> VarT m a c #

Applicative m => Functor (VarT m b) Source #

You can transform the output value of any var:

>>> let v = 1 >>> fmap (*3) (accumulate (+) 0)
>>> testVarOver v [(),(),()]
3
6
9
Instance details

Defined in Control.Varying.Core

Methods

fmap :: (a -> b0) -> VarT m b a -> VarT m b b0 #

(<$) :: a -> VarT m b b0 -> VarT m b a #

Applicative m => Applicative (VarT m a) Source #

Vars are applicative.

>>> let v = (,) <$> pure True <*> pure "Applicative"
>>> testVarOver v [()]
(True,"Applicative")

Note - checkout the proofs

Instance details

Defined in Control.Varying.Core

Methods

pure :: a0 -> VarT m a a0 #

(<*>) :: VarT m a (a0 -> b) -> VarT m a a0 -> VarT m a b #

liftA2 :: (a0 -> b -> c) -> VarT m a a0 -> VarT m a b -> VarT m a c #

(*>) :: VarT m a a0 -> VarT m a b -> VarT m a b #

(<*) :: VarT m a a0 -> VarT m a b -> VarT m a a0 #

(Monad m, Floating b) => Floating (VarT m a b) Source #

Vars can be written as floats.

>>> let v = pi >>> accumulate (*) 1 >>> arr round
>>> testVarOver v [(),(),()]
3
10
31
Instance details

Defined in Control.Varying.Core

Methods

pi :: VarT m a b #

exp :: VarT m a b -> VarT m a b #

log :: VarT m a b -> VarT m a b #

sqrt :: VarT m a b -> VarT m a b #

(**) :: VarT m a b -> VarT m a b -> VarT m a b #

logBase :: VarT m a b -> VarT m a b -> VarT m a b #

sin :: VarT m a b -> VarT m a b #

cos :: VarT m a b -> VarT m a b #

tan :: VarT m a b -> VarT m a b #

asin :: VarT m a b -> VarT m a b #

acos :: VarT m a b -> VarT m a b #

atan :: VarT m a b -> VarT m a b #

sinh :: VarT m a b -> VarT m a b #

cosh :: VarT m a b -> VarT m a b #

tanh :: VarT m a b -> VarT m a b #

asinh :: VarT m a b -> VarT m a b #

acosh :: VarT m a b -> VarT m a b #

atanh :: VarT m a b -> VarT m a b #

log1p :: VarT m a b -> VarT m a b #

expm1 :: VarT m a b -> VarT m a b #

log1pexp :: VarT m a b -> VarT m a b #

log1mexp :: VarT m a b -> VarT m a b #

(Monad m, Fractional b) => Fractional (VarT m a b) Source #

Vars can be written as fractionals.

>>> let v = 2.5 >>> accumulate (/) 10
>>> testVarOver v [(),(),()]
4.0
1.6
0.64
Instance details

Defined in Control.Varying.Core

Methods

(/) :: VarT m a b -> VarT m a b -> VarT m a b #

recip :: VarT m a b -> VarT m a b #

fromRational :: Rational -> VarT m a b #

(Monad m, Num b) => Num (VarT m a b) Source #

Vars can be written as numbers.

>>> let v = 1 >>> accumulate (+) 0
>>> testVarOver v [(),(),()]
1
2
3
Instance details

Defined in Control.Varying.Core

Methods

(+) :: VarT m a b -> VarT m a b -> VarT m a b #

(-) :: VarT m a b -> VarT m a b -> VarT m a b #

(*) :: VarT m a b -> VarT m a b -> VarT m a b #

negate :: VarT m a b -> VarT m a b #

abs :: VarT m a b -> VarT m a b #

signum :: VarT m a b -> VarT m a b #

fromInteger :: Integer -> VarT m a b #

(Applicative m, Semigroup b) => Semigroup (VarT m a b) Source #

Vars can be semigroups

>>> let v = var (const "Hello ") <> var (const "World!")
>>> testVarOver v [()]
"Hello World!"
Instance details

Defined in Control.Varying.Core

Methods

(<>) :: VarT m a b -> VarT m a b -> VarT m a b #

sconcat :: NonEmpty (VarT m a b) -> VarT m a b #

stimes :: Integral b0 => b0 -> VarT m a b -> VarT m a b #

(Applicative m, Monoid b) => Monoid (VarT m a b) Source #

Vars can be monoids

>>> let v = var (const "Hello ") `mappend` var (const "World!")
>>> testVarOver v [()]
"Hello World!"
Instance details

Defined in Control.Varying.Core

Methods

mempty :: VarT m a b #

mappend :: VarT m a b -> VarT m a b -> VarT m a b #

mconcat :: [VarT m a b] -> VarT m a b #

Creating vars

You can create a pure var by lifting a function (a -> b) with var:

arr (+1) == var (+1) :: VarT m Int Int

var is a parameterized version of arr.

You can create a monadic var by lifting a monadic computation (a -> m b) using varM:

getsFile :: VarT IO FilePath String
getsFile = varM readFile

You can create either with the raw constructor. You can also create your own combinators using the raw constructor, as it allows you full control over how vars are stepped and sampled:

delay :: Monad m => b -> VarT m a b -> VarT m a b
delay b v = VarT $ \a -> return (b, go a v)
    where go a v' = VarT $ \a' -> do (b', v'') <- runVarT v' a
                                     return (b', go a' v'')

done :: Applicative m => b -> VarT m a b Source #

Lift a constant value to a var.

var :: Applicative m => (a -> b) -> VarT m a b Source #

Lift a pure computation to a var. This is arr parameterized over the a `VarT m` b arrow.

arr :: Arrow a => (b -> c) -> a b c #

Lift a function to an arrow.

varM :: Monad m => (a -> m b) -> VarT m a b Source #

Lift a monadic computation to a var. This is arrM parameterized over the a `VarT m` b arrow.

mkState Source #

Arguments

:: Monad m 
=> (a -> s -> (b, s))

state transformer

-> s

intial state

-> VarT m a b 

Create a var from a state transformer.

Composing vars

You can compose vars together using Category's >>> and <<<. The "right plug" (>>>) takes the output from a var on the left and "plugs" it into the input of the var on the right. The "left plug" does the same thing in the opposite direction. This allows you to write vars that read naturally.

(<<<) :: Category cat => cat b c -> cat a b -> cat a c infixr 1 #

Right-to-left composition

(>>>) :: Category cat => cat a b -> cat b c -> cat a c infixr 1 #

Left-to-right composition

Adjusting and accumulating

delay :: Monad m => b -> VarT m a b -> VarT m a b Source #

Delays the given var by one sample using the argument as the first sample.

>>> testVarOver (delay 0 id) [1,2,3]
0
1
2

This enables the programmer to create vars that depend on themselves for values. For example:

>>> let v = delay 0 v + 1 in testVarOver v [1,1,1]
1
2
3

accumulate :: Monad m => (c -> b -> c) -> c -> VarT m b c Source #

Accumulates input values using a folding function and yields that accumulated value each sample. This is analogous to a stepwise foldl.

>>> testVarOver (accumulate (++) []) $ words "hey there man"
"hey"
"heythere"
"heythereman"
>>> print $ foldl (++) [] $ words "hey there man"
"heythereman"

Sampling vars (running and other entry points)

To sample a var simply run it in the desired monad with runVarT. This will produce a sample value and a new var.

>>> :{
do let v0 = accumulate (+) 0
   (b, v1) <- runVarT v0 1
   print b
   (c, v2) <- runVarT v1 b
   print c
   (d,  _) <- runVarT v2 c
   print d
>>> :}
1
2
4

scanVar :: Monad m => VarT m a b -> [a] -> m ([b], VarT m a b) Source #

Run the var over the input values, gathering the output values in a list.

>>> let Identity (outputs, _) = scanVar (accumulate (+) 0) [1,1,1,1]
>>> print outputs
[1,2,3,4]

stepMany :: Monad m => VarT m a b -> [a] -> a -> m (b, VarT m a b) Source #

Iterate a var over a list of input until all input is consumed, then iterate the var using one single input. Returns the resulting output value and the new var.

>>> let Identity (outputs, _) = stepMany (accumulate (+) 0) [1,1,1] 1
>>> print outputs
4

Debugging and tracing vars in flight

vtrace :: (Applicative a, Show b) => VarT a b b Source #

Trace the sample value of a var and pass it along as output. This is very useful for debugging graphs of vars. The (v|vs|vf)trace family of vars use trace under the hood, so the value is only traced when evaluated.

>>> let v = id >>> vtrace
>>> testVarOver v [1,2,3]
1
1
2
2
3
3

vstrace :: (Applicative a, Show b) => String -> VarT a b b Source #

Trace the sample value of a var with a prefix and pass the sample along as output. This is very useful for debugging graphs of vars.

>>> let v = id >>> vstrace "test: "
>>> testVarOver v [1,2,3]
test: 1
1
test: 2
2
test: 3
3

vftrace :: Applicative a => (b -> String) -> VarT a b b Source #

Trace the sample value using a custom show-like function. This is useful when you would like to debug a var that uses values that don't have show instances.

>>> newtype NotShowableInt = NotShowableInt { unNotShowableInt :: Int }
>>> let v = id >>> vftrace (("NotShowableInt: " ++) . show . unNotShowableInt)
>>> let as = map NotShowableInt [1,1,1]
>>> bs <- fst <$> scanVar v as
>>> -- We need to do something to evaluate these output values...
>>> print $ sum $ map unNotShowableInt bs
NotShowableInt: 1
NotShowableInt: 1
NotShowableInt: 1
3

testVarOver :: (Monad m, MonadIO m, Show b) => VarT m a b -> [a] -> m () Source #

Run a var in IO over some input, printing the output each step. This is the function we've been using throughout this documentation.

Proofs of the Applicative laws

Identity

pure id <*> va = va
-- Definition of pure
VarT (\_ -> pure (id, pure id)) <*> v
-- Definition of <*>
VarT (\x -> do
  (f, vf') <- runVarT (VarT (\_ -> pure (id, pure id))) x
  (a, va') <- runVarT va x
  pure (f a, vf' <*> va'))
-- Newtype
VarT (\x -> do
  (f, vf') <- (\_ -> pure (id, pure id)) x
  (a, va') <- runVarT va x
  pure (f a, vf' <*> va'))
-- Application
VarT (\x -> do
  (f, vf') <- pure (id, pure id)
  (a, va') <- runVarT va x
  pure (f a, vf' <*> va'))
-- pure x >>= f = f x
VarT (\x -> do
  (a, va') <- runVarT va x
  pure (id a, pure id <*> va'))
-- Definition of id
VarT (\x -> do
  (a, va') <- runVarT va x
  pure (a, pure id <*> va'))
-- Coinduction
VarT (\x -> do
  (a, va') <- runVarT va x
  pure (a, va'))
-- f >>= pure = f
VarT (\x -> runVarT va x)
-- Eta reduction
VarT (runVarT va)
-- Newtype
va

Composition

pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
-- Definition of pure
VarT (\_ -> pure ((.), pure (.))) <*> u <*> v <*> w
-- Definition of <*>
VarT (\x -> do
  (h, t)  <- runVarT (VarT (\_ -> pure ((.), pure (.)))) x
  (f, u') <- runVarT u x
  pure (h f, t <*> u')) <*> v <*> w
-- Newtype
VarT (\x -> do
  (h, t)  <- (\_ -> pure ((.), pure (.))) x
  (f, u') <- runVarT u x
  pure (h f, t <*> u')) <*> v <*> w
-- Application
VarT (\x -> do
  (h, t)  <- pure ((.), pure (.)))
  (f, u') <- runVarT u x
  pure (h f, t <*> u')) <*> v <*> w
-- pure x >>= f = f x
VarT (\x -> do
  (f, u') <- runVarT u x
  pure ((.) f, pure (.) <*> u')) <*> v <*> w
-- Definition of <*>
VarT (\x -> do
  (h, t) <-
    runVarT
      (VarT (\y -> do
        (f, u') <- runVarT u y
        pure ((.) f, pure (.) <*> u'))) x
  (g, v') <- runVarT v x
  pure (h g, t <*> v')) <*> w
-- Newtype
VarT (\x -> do
  (h, t) <-
    (\y -> do
      (f, u') <- runVarT u y
      pure ((.) f, pure (.) <*> u')) x
  (g, v') <- runVarT v x
  pure (h g, t <*> v')) <*> w
-- Application
VarT (\x -> do
  (h, t) <- do
    (f, u') <- runVarT u x
    pure ((.) f, pure (.) <*> u')
  (g, v') <- runVarT v x
  pure (h g, t <*> v')) <*> w
-- (f >=> g) >=> h = f >=> (g >=> h)
VarT (\x -> do
  (f, u') <- runVarT u x
  (h, t)  <- pure ((.) f, pure (.) <*> u')
  (g, v') <- runVarT v x
  pure (h g, t <*> v')) <*> w
-- pure x >>= f = f x
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  pure ((.) f g, pure (.) <*> u' <*> v')) <*> w
-- Definition of <*>
VarT (\x -> do
  (h, t) <-
    runVarT
      (VarT (\y -> do
        (f, u') <- runVarT u y
        (g, v') <- runVarT v y
        pure ((.) f g, pure (.) <*> u' <*> v'))) x
  (a, w') <- runVarT w x
  pure (h a, t <*> w'))
-- Newtype
VarT (\x -> do
  (h, t) <-
    (\y -> do
      (f, u') <- runVarT u y
      (g, v') <- runVarT v y
      pure ((.) f g, pure (.) <*> u' <*> v')) x
  (a, w') <- runVarT w x
  pure (h a, t <*> w'))
-- Application
VarT (\x -> do
  (h, t) <- do
    (f, u') <- runVarT u x
    (g, v') <- runVarT v x
    pure ((.) f g, pure (.) <*> u' <*> v'))
  (a, w') <- runVarT w x
  pure (h a, t <*> w'))
-- (f >=> g) >=> h = f >=> (g >=> h)
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  (h, t)  <- pure ((.) f g, pure (.) <*> u' <*> v'))
  (a, w') <- runVarT w x
  pure (h a, t <*> w'))
-- pure x >>= f = f x
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  (a, w') <- runVarT w x
  pure ((.) f g a, pure (.) <*> u' <*> v' <*> w'))
-- Definition of .
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  (a, w') <- runVarT w x
  pure (f (g a), pure (.) <*> u' <*> v' <*> w'))
-- Coinduction
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  (a, w') <- runVarT w x
  pure (f (g a), u' <*> (v' <*> w')))
-- pure x >>= f = f
VarT (\x -> do
  (f, u') <- runVarT u x
  (g, v') <- runVarT v x
  (a, w') <- runVarT w x
  (b, vw) <- pure (g a, v' <*> w')
  pure (f b, u' <*> vw))
-- (f >=> g) >=> h = f >=> (g >=> h)
VarT (\x -> do
  (f, u') <- runVarT u x
  (b, vw) <- do
    (g, v') <- runVarT v x
    (a, w') <- runVarT w x
    pure (g a, v' <*> w')
  pure (f b, u' <*> vw))
-- Abstraction
VarT (\x -> do
  (f, u') <- runVarT u x
  (b, vw) <-
    (\y -> do
      (g, v') <- runVarT v y
      (a, w') <- runVarT w y)
      pure (g a, v' <*> w')) x
  pure (f b, u' <*> vw))
-- Newtype
VarT (\x -> do
  (f, u') <- runVarT u x
  (b, vw) <-
    runVarT
      (VarT (\y -> do
        (g, v') <- runVarT v y
        (a, w') <- runVarT w y)
        pure (g a, v' <*> w')) x
  pure (f b, u' <*> vw))
-- Definition of <*>
VarT (\x -> do
  (f, u') <- runVarT u x
  (b, vw) <- runVarT (v <*> w) x
  pure (f b, u' <*> vw))
-- Definition of <*>
u <*> (v <*> w)

Homomorphism

pure f <*> pure a = pure (f a)
-- Definition of pure
VarT (\_ -> pure (f, pure f)) <*> pure a
-- Definition of pure
VarT (\_ -> pure (f, pure f)) <*> VarT (\_ -> pure (a, pure a))
-- Definition of <*>
VarT (\x -> do
  (f', vf') <- runVarT (VarT (\_ -> pure (f, pure f))) x
  (a', va') <- runVarT (VarT (\_ -> pure (a, pure a))) x
  pure (f' a', vf' <*> va'))
-- Newtype
VarT (\x -> do
  (f', vf') <- (\_ -> pure (f, pure f)) x
  (a', va') <- runVarT (VarT (\_ -> pure (a, pure a))) x
  pure (f' a', vf' <*> va'))
-- Application
VarT (\x -> do
  (f', vf') <- pure (f, pure f)
  (a', va') <- runVarT (VarT (\_ -> pure (a, pure a))) x
  pure (f' a', vf' <*> va'))
-- pure x >>= f = f x
VarT (\x -> do
  (a', va') <- runVarT (VarT (\_ -> pure (a, pure a))) x
  pure (f a', pure f <*> va'))
-- Newtype
VarT (\x -> do
  (a', va') <- (\_ -> pure (a, pure a)) x
  pure (f a', pure f <*> va'))
-- Application
VarT (\x -> do
  (a', va') <- pure (a, pure a)
  pure (f a', pure f <*> va'))
-- pure x >>= f = f x
VarT (\x -> pure (f a, pure f <*> pure a))
-- Coinduction
VarT (\x -> pure (f a, pure (f a)))
-- Definition of pure
pure (f a)

Interchange

u <*> pure y = pure ($ y) <*> u
-- Definition of <*>
VarT (\x -> do
  (f, u') <- runVarT u x
  (a, y') <- runVarT (pure y) x
  pure (f a, u' <*> y'))
-- Definition of pure
VarT (\x -> do
  (f, u') <- runVarT u x
  (a, y') <- runVarT (VarT (\_ -> pure (y, pure y))) x
  pure (f a, u' <*> y'))
-- Newtype
VarT (\x -> do
  (f, u') <- runVarT u x
  (a, y') <- (\_ -> pure (y, pure y)) x
  pure (f a, u' <*> y'))
-- Application
VarT (\x -> do
  (f, u') <- runVarT u x
  (a, y') <- pure (y, pure y))
  pure (f a, u' <*> y'))
-- pure x >>= f = f
VarT (\x -> do
  (f, u') <- runVarT u x
  pure (f y, u' <*> pure y))
-- Coinduction
VarT (\x -> do
  (f, u') <- runVarT u x
  pure (f y, pure ($ y) <*> u'))
-- Definition of $
VarT (\x -> do
  (f, u') <- runVarT u x
  pure (($ y) f, pure ($ y) <*> u')
-- pure x >>= f = f
VarT (\x -> do
  (g, y') <- pure (($ y), pure ($ y))
  (f, u') <- runVarT u x
  pure (g f, y' <*> u')
-- Abstraction
VarT (\x -> do
  (g, y') <- (\_ -> pure (($ y), pure ($ y))) x
  (f, u') <- runVarT u x
  pure (g f, y' <*> u')
-- Newtype
VarT (\x -> do
  (g, y') <- runVarT (VarT (\_ -> pure (($ y), pure ($ y)))) x
  (f, u') <- runVarT u x
  pure (g f, y' <*> u')
-- Definition of <*>
VarT (\_ -> pure (($ y), pure ($ y))) <*> u
-- Definition of pure
pure ($ y) <*> u