Copyright | (c) 2015 Schell Scivally |
---|---|
License | MIT |
Maintainer | Schell Scivally <schell@takt.com> |
Safe Haskell | None |
Language | Haskell2010 |
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
- type Var a b = VarT Identity a b
- newtype VarT m a b = VarT {}
- done :: Applicative m => b -> VarT m a b
- var :: Applicative m => (a -> b) -> VarT m a b
- arr :: Arrow a => (b -> c) -> a b c
- varM :: Monad m => (a -> m b) -> VarT m a b
- mkState :: Monad m => (a -> s -> (b, s)) -> s -> VarT m a b
- (<<<) :: Category cat => cat b c -> cat a b -> cat a c
- (>>>) :: Category cat => cat a b -> cat b c -> cat a c
- delay :: Monad m => b -> VarT m a b -> VarT m a b
- accumulate :: Monad m => (c -> b -> c) -> c -> VarT m b c
- scanVar :: Monad m => VarT m a b -> [a] -> m ([b], VarT m a b)
- stepMany :: Monad m => VarT m a b -> [a] -> a -> m (b, VarT m a b)
- vtrace :: (Applicative a, Show b) => VarT a b b
- vstrace :: (Applicative a, Show b) => String -> VarT a b b
- vftrace :: Applicative a => (b -> String) -> VarT a b b
- testVarOver :: (Monad m, MonadIO m, Show b) => VarT m a b -> [a] -> m ()
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
.
A continuously varying value, with effects. It's a kind of Mealy machine (an automaton).
VarT | Run a |
Instances
Monad m => Arrow (VarT m) Source # | Vars are arrows, which means you can use proc notation, among other meanings.
which is equivalent to
|
MonadPlus m => ArrowZero (VarT m) Source # | |
Defined in Control.Varying.Core | |
MonadPlus m => ArrowPlus (VarT m) Source # | |
Monad m => ArrowChoice (VarT m) Source # | |
MonadFix m => ArrowLoop (VarT m) Source # | Inputs can depend on outputs as long as no time-travel is required. This isn't the best example but it does make a good test case:
|
Defined in Control.Varying.Core | |
Monad m => Category (VarT m :: Type -> Type -> Type) Source # | A var is a category. id = var id f . g = g >>> f or f . g = f <<< g
|
Applicative m => Functor (VarT m b) Source # | You can transform the output value of any var:
|
Applicative m => Applicative (VarT m a) Source # | Vars are applicative.
Note - checkout the proofs |
(Monad m, Floating b) => Floating (VarT m a b) Source # | Vars can be written as floats.
|
Defined in Control.Varying.Core 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 # | |
(Monad m, Fractional b) => Fractional (VarT m a b) Source # | Vars can be written as fractionals.
|
(Monad m, Num b) => Num (VarT m a b) Source # | Vars can be written as numbers.
|
Defined in Control.Varying.Core | |
(Applicative m, Semigroup b) => Semigroup (VarT m a b) Source # | Vars can be semigroups
|
(Applicative m, Monoid b) => Monoid (VarT m a b) Source # | Vars can be monoids
|
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.
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.
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.
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