-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A modal FRP language -- -- This library implements the Rattus programming language as an embedded -- DSL. To this end the library provides a GHC plugin that performs the -- additional checks that are necessary for Rattus. What follows is a -- brief introduction to the language and its usage. A more detailed -- introduction can be found in this paper. -- -- Rattus is a functional reactive programming (FRP) language that uses -- modal types to ensure operational properties that are crucial for -- reactive programs: productivity (in each computation step, the program -- makes progress), causality (output depends only on current and earlier -- input), and no implicit space leaks (programs do not implicitly retain -- memory over time). -- -- To ensure these properties, Rattus uses the type modality O -- to express the concept of time at the type level. Intuitively -- speaking, a value of type O a represents a computation that -- will produce a value of type a in the next time step. -- Additionally, the language also features the Box type -- modality. A value of type Box a is a time-independent -- computation that can be executed at any time to produce a value of -- type a. -- -- For example, the type of streams is defined as -- --
-- data Str a = a ::: (O (Str a)) ---- -- So the head of the stream is available now, but its tail is only -- available in the next time step. Writing a map function for -- this type of streams, requires us to use the Box modality: -- --
-- map :: Box (a -> b) -> Str a -> Str b -- map f (x ::: xs) = unbox f x ::: delay (map f (adv xs)) ---- -- This makes sure that the function f that we give to -- map is available at any time in the future. -- -- The core of the language is defined in the module -- Rattus.Primitives. Note that the operations on O and -- Box have non-standard typing rules. Therefore, this library -- provides a compiler plugin that checks these non-standard typing -- rules. To write Rattus programs, one must enable this plugin via the -- GHC option -fplugin=Rattus.Plugin, e.g. by including the -- following line in the source file (for better error messages we also -- suggest using the option -g2): -- --
-- {-# OPTIONS -fplugin=Rattus.Plugin #-}
--
--
-- In addition, one must annotate the functions that are written in
-- Rattus:
--
--
-- {-# ANN myFunction Rattus #-}
--
--
-- Or annotate the whole module as a Rattus module:
--
--
-- {-# ANN module Rattus #-}
--
--
-- Below is a minimal Rattus program using the Rattus.Stream
-- module for programming with streams:
--
--
-- {-# OPTIONS -fplugin=Rattus.Plugin #-}
--
-- import Rattus
-- import Rattus.Stream
--
-- {-# ANN sums Rattus #-}
-- sums :: Str Int -> Str Int
-- sums = scan (box (+)) 0
--
--
-- The source code of the Rattus.Stream module provides more
-- examples on how to program in Rattus.
@package Rattus
@version 0.2
-- | The plugin to make it all work.
module Rattus.Plugin
-- | Use this to enable Rattus' plugin, either by supplying the option
-- -fplugin=Rattus.Plugin directly to GHC. or by including the
-- following pragma in each source file:
--
--
-- {-# OPTIONS -fplugin=Rattus.Plugin #-}
--
plugin :: Plugin
-- | Use this type to mark a Haskell function definition as a Rattus
-- function:
--
--
-- {-# ANN myFunction Rattus #-}
--
--
-- Or mark a whole module as consisting of Rattus functions only:
--
--
-- {-# ANN module Rattus #-}
--
--
-- If you use the latter option, you can mark exceptions (i.e. functions
-- that should be treated as ordinary Haskell function definitions) as
-- follows:
--
--
-- {-# ANN myFunction NotRattus #-}
--
--
-- By default all Rattus functions are checked for use of lazy data
-- types, since these may cause memory leaks. If any lazy data types are
-- used, a warning is issued. These warnings can be disabled by
-- annotating the module or the function with AllowLazyData
--
--
-- {-# ANN myFunction AllowLazyData #-}
--
-- {-# ANN module AllowLazyData #-}
--
data Rattus
Rattus :: Rattus
NotRattus :: Rattus
AllowLazyData :: Rattus
instance GHC.Classes.Eq Rattus.Plugin.Rattus
instance GHC.Show.Show Rattus.Plugin.Rattus
instance Data.Data.Data Rattus.Plugin.Rattus
-- | The language primitives of Rattus. Note that the Rattus types
-- delay, adv, and box are more restrictive that the
-- Haskell types that are indicated. The more stricter Rattus typing
-- rules for these primitives are given. To ensure that your program
-- adheres to these stricter typing rules, use the plugin in
-- Rattus.Plugin so that GHC will check these stricter typing
-- rules.
module Rattus.Primitives
-- | The "later" type modality. A value of type O a is a
-- computation that produces a value of type a in the next time
-- step. Use delay and adv to construct and consume
-- O-types.
data O a
-- | The "stable" type modality. A value of type Box a is a
-- time-independent computation that produces a value of type a.
-- Use box and unbox to construct and consume
-- Box-types.
data Box a
-- | This is the constructor for the "later" modality O:
--
-- -- Γ ✓ ⊢ t :: 𝜏 -- -------------------- -- Γ ⊢ delay t :: O 𝜏 --delay :: a -> O a -- | This is the eliminator for the "later" modality O: -- --
-- Γ ⊢ t :: O 𝜏 -- --------------------- -- Γ ✓ Γ' ⊢ adv t :: 𝜏 --adv :: O a -> a -- | This is the constructor for the "stable" modality Box: -- --
-- Γ☐ ⊢ t :: 𝜏 -- -------------------- -- Γ ⊢ box t :: Box 𝜏 ---- -- where Γ☐ is obtained from Γ by removing ✓ and any variables x :: -- 𝜏, where 𝜏 is not a stable type. box :: a -> Box a -- | This is the eliminator for the "stable" modality Box: -- --
-- Γ ⊢ t :: Box 𝜏 -- ------------------ -- Γ ⊢ unbox t :: 𝜏 --unbox :: Box a -> a -- | A type is Stable if it is a strict type and the later -- modality O and function types only occur under Box. -- -- For example, these types are stable: Int, Box (a -> -- b), Box (O Int), Box (Str a -> Str b). -- -- But these types are not stable: [Int] (because the list type -- is not strict), Int -> Int, (function type is not stable), -- O Int, Str Int. class Stable a -- | This module provides a variant of the standard Arrow type class -- with a different arr method so that it can be implemented for -- signal functions in Rattus. module Rattus.Arrow -- | Variant of the standard Arrow type class with a different -- arr method so that it can be implemented for signal functions -- in Rattus. class Category a => Arrow a -- | Lift a function to an arrow. It is here the definition of the -- Arrow class differs from the standard one. The function to be -- lifted has to be boxed. arrBox :: Arrow a => Box (b -> c) -> a b c -- | Send the first component of the input through the argument arrow, and -- copy the rest unchanged to the output. first :: Arrow a => a b c -> a (b, d) (c, d) -- | A mirror image of first. -- -- The default definition may be overridden with a more efficient version -- if desired. second :: Arrow a => a b c -> a (d, b) (d, c) -- | Split the input between the two argument arrows and combine their -- output. Note that this is in general not a functor. (***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c') -- | Fanout: send the input to both argument arrows and combine their -- output. -- -- The default definition may be overridden with a more efficient version -- if desired. (&&&) :: Arrow a => a b c -> a b c' -> a b (c, c') -- | This combinator is subject to the same restrictions as the box -- primitive of Rattus. That is, -- --
-- Γ☐ ⊢ t :: b -> c -- -------------------- -- Γ ⊢ arr t :: a b c ---- -- where Γ☐ is obtained from Γ by removing ✓ and any variables x :: -- 𝜏, where 𝜏 is not a stable type. arr :: Arrow a => (b -> c) -> a b c -- | The identity arrow, which plays the role of return in arrow -- notation. returnA :: Arrow a => a b b -- | This module contains strict versions of some standard data structures. module Rattus.Strict -- | Strict list type. data List a Nil :: List a (:!) :: !a -> !List a -> List a infixr 8 :! -- | Reverse a list. reverse' :: List a -> List a -- | Append two lists. (+++) :: List a -> List a -> List a -- | Returns Nothing' on an empty list or Just' -- a where a is the first element of the list. listToMaybe' :: List a -> Maybe' a -- | A version of map which can throw out elements. In particular, -- the function argument returns something of type Maybe' -- b. If this is Nothing', no element is added on to the -- result list. If it is Just' b, then b is -- included in the result list. mapMaybe' :: (a -> Maybe' b) -> List a -> List b -- | Strict pair type. data a :* b (:*) :: !a -> !b -> (:*) a b infixr 2 :* infixr 2 :* -- | Strict variant of Maybe. data Maybe' a Just' :: !a -> Maybe' a Nothing' :: Maybe' a -- | takes a default value, a function, and a Maybe' value. If the -- Maybe' value is Nothing', the function returns the -- default value. Otherwise, it applies the function to the value inside -- the Just' and returns the result. maybe' :: b -> (a -> b) -> Maybe' a -> b -- | First projection function. fst' :: (a :* b) -> a -- | Second projection function. snd' :: (a :* b) -> b instance GHC.Float.RealFloat a => Data.VectorSpace.VectorSpace (a Rattus.Strict.:* a) a instance GHC.Base.Functor ((Rattus.Strict.:*) a) instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (a Rattus.Strict.:* b) instance Data.Foldable.Foldable Rattus.Strict.List instance GHC.Base.Functor Rattus.Strict.List -- | The bare-bones Rattus language. To program with streams and events, -- you can use Rattus.Stream and Rattus.Events; to program -- with Yampa-style signal functions, you can use Rattus.Yampa. module Rattus -- | Use this type to mark a Haskell function definition as a Rattus -- function: -- --
-- {-# ANN myFunction Rattus #-}
--
--
-- Or mark a whole module as consisting of Rattus functions only:
--
--
-- {-# ANN module Rattus #-}
--
--
-- If you use the latter option, you can mark exceptions (i.e. functions
-- that should be treated as ordinary Haskell function definitions) as
-- follows:
--
--
-- {-# ANN myFunction NotRattus #-}
--
--
-- By default all Rattus functions are checked for use of lazy data
-- types, since these may cause memory leaks. If any lazy data types are
-- used, a warning is issued. These warnings can be disabled by
-- annotating the module or the function with AllowLazyData
--
--
-- {-# ANN myFunction AllowLazyData #-}
--
-- {-# ANN module AllowLazyData #-}
--
data Rattus
Rattus :: Rattus
NotRattus :: Rattus
AllowLazyData :: Rattus
-- | Applicative operator for Box.
(|*|) :: Box (a -> b) -> Box a -> Box b
-- | Variant of |*| where the argument is of a stable type..
(|**) :: Stable a => Box (a -> b) -> a -> Box b
-- | Applicative operator for O.
(<*>) :: O (a -> b) -> O a -> O b
-- | Variant of <*> where the argument is of a stable type..
(<**) :: Stable a => O (a -> b) -> a -> O b
-- | Programming with streams.
module Rattus.Stream
-- | Apply a function to each element of a stream.
map :: Box (a -> b) -> Str a -> Str b
-- | Get the first element (= head) of a stream.
hd :: Str a -> a
-- | Get the tail of a stream, i.e. the remainder after removing the first
-- element.
tl :: Str a -> O (Str a)
-- | Construct a stream that has the same given value at each step.
const :: Stable a => a -> Str a
-- | Variant of const that allows any type a as argument as
-- long as it is boxed.
constBox :: Box a -> Str a
-- | Given a value a and a stream as, this function produces a stream that
-- behaves like
shift :: Stable a => a -> Str a -> Str a
-- | Given a list [a1, ..., an] of elements and a stream
-- xs this function constructs a stream that starts with the
-- elements a1, ..., an, and then proceeds as xs. In
-- particular, this means that the ith element of the original stream
-- xs is the (i+n)th element of the new stream. In other words
-- shiftMany behaves like repeatedly applying shift for
-- each element in the list.
shiftMany :: Stable a => List a -> Str a -> Str a
-- | Similar to Haskell's scanl.
--
-- -- scan (box f) x (v1 ::: v2 ::: v3 ::: ... ) == (x `f` v1) ::: ((x `f` v1) `f` v2) ::: ... ---- -- Note: Unlike scanl, scan starts with x f -- v1, not x. scan :: Stable b => Box (b -> a -> b) -> b -> Str a -> Str b -- | scanMap is a composition of map and scan: -- --
-- scanMap f g x === map g . scan f x --scanMap :: Stable b => Box (b -> a -> b) -> Box (b -> c) -> b -> Str a -> Str c -- | scanMap2 is similar to scanMap but takes two input -- streams. scanMap2 :: Stable b => Box (b -> a1 -> a2 -> b) -> Box (b -> c) -> b -> Str a1 -> Str a2 -> Str c -- | Str a is a stream of values of type a. data Str a (:::) :: !a -> O (Str a) -> Str a -- | Similar to zipWith on Haskell lists. zipWith :: Box (a -> b -> c) -> Str a -> Str b -> Str c -- | Similar to zip on Haskell lists. zip :: Str a -> Str b -> Str (a :* b) -- | Construct a stream by repeatedly applying a function to a given start -- element. That is, unfold (box f) x will produce the stream -- x ::: f x ::: f (f x) ::: ... unfold :: Stable a => Box (a -> a) -> a -> Str a -- | Filter out elements from a stream according to a predicate. filter :: Box (a -> Bool) -> Str a -> Str (Maybe' a) -- | Calculates an approximation of an integral of the stream of type -- Str a (the y-axis), where the stream of type Str s -- provides the distance between measurements (i.e. the distance along -- the y axis). integral :: (Stable a, VectorSpace a s) => a -> Str s -> Str a -> Str a -- | Programming with many-shot events, i.e. events that may occur zero or -- more times. module Rattus.Events -- | Apply a function to the values of the event (every time it occurs). map :: Box (a -> b) -> Events a -> Events b -- | An event that will never occur. never :: Events a -- | switch s e will behave like s but switches to -- s'$ every time the event e occurs with some value -- s'@. switch :: Str a -> Events (Str a) -> Str a -- | Like switch but works on stream functions instead of streams. -- That is, switchTrans s e will behave like s but -- switches to s'$ every time the event e occurs with some -- value s'@. switchTrans :: (Str a -> Str b) -> Events (Str a -> Str b) -> Str a -> Str b -- | Events are simply streams of Maybe's. type Events a = Str (Maybe' a) -- | Trigger an event as every time the given predicate turns true on the -- given stream. The value of the event is the same as that of the stream -- at that time. trigger :: Box (a -> Bool) -> Str a -> Events a -- | Trigger an event every time the given function produces a Just' -- value. triggerMap :: Box (a -> Maybe' b) -> Str a -> Events b -- | Programming with single shot events, i.e. events that may occur at -- most once. module Rattus.Event -- | Apply a function to the value of the event (if it ever occurs). map :: Box (a -> b) -> Event a -> Event b -- | An event that will never occur. never :: Event a -- | switch s e will behave like s until the event -- e occurs with value s', in which case it will behave -- as s'. switch :: Str a -> Event (Str a) -> Str a -- | Like switch but works on stream functions instead of streams. -- That is, switchTrans s e will behave like s until -- the event e occurs with value s', in which case it -- will behave as s'. switchTrans :: (Str a -> Str b) -> Event (Str a -> Str b) -> Str a -> Str b -- | Turn a stream of Maybe's into a stream of events. Each such -- event behaves as if created by firstJust. whenJust :: Str (Maybe' a) -> Str (Event a) -- | An event may either occur now or later. data Event a Now :: !a -> Event a Wait :: O (Event a) -> Event a -- | Synchronise two events. The resulting event occurs after both events -- have occurred (coinciding with whichever event occurred last. await :: (Stable a, Stable b) => Event a -> Event b -> Event (a :* b) -- | Trigger an event as soon as the given predicate turns true on the -- given stream. The value of the event is the same as that of the stream -- at that time. trigger :: Box (a -> Bool) -> Str a -> Event a -- | Trigger an event as soon as the given function produces a Just' -- value. triggerMap :: Box (a -> Maybe' b) -> Str a -> Event b -- | A simply Yampa-like library for signal functions. module Rattus.Yampa -- | Signal functions from inputs of type a to outputs of type -- b. data SF a b -- | The identity signal function that does nothing. identity :: SF a a -- | Compose two signal functions. compose :: SF b c -> SF a b -> SF a c -- | switch s f behaves like s composed with arr -- fst until s produces a value of the form Just' -- c in the second component. From then on it behaves like $f c@. switch :: SF a (b :* Maybe' c) -> Box (c -> SF a b) -> SF a b -- | rSwitch s behaves like s, but every time the second -- input is of the form Just' s' it will change behaviour to -- s'. rSwitch :: SF a b -> SF (a :* Maybe' (SF a b)) b -- | Constant signal function. constant :: Stable b => b -> SF a b -- | Loop with an initial value for the signal being fed back. -- -- Note: The type of loopPre is different from Yampa's as we -- need the O type here. loopPre :: c -> SF (a :* c) (b :* O c) -> SF a b -- | Run a signal function for one step. stepSF :: SF a b -> DTime -> a -> O (SF a b) :* b -- | Override initial value of input signal. initially :: a -> SF a a -- | Compute the integral of a signal. The first argument is the offset. integral :: (Stable a, VectorSpace a s) => a -> SF a a -- | The output at time zero is the first argument, and from that point on -- it behaves like the signal function passed as second argument. (-->) :: b -> SF a b -> SF a b -- | Insert a sample in the output, and from that point on, behave like the -- given signal function. -- -- Note: The type of -:> is different from Yampa's: The second -- argument must be delayed (or boxed). (-:>) :: b -> O (SF a b) -> SF a b -- | The input at time zero is the first argument, and from that point on -- it behaves like the signal function passed as second argument. (>--) :: a -> SF a b -> SF a b -- | Apply a function to the first output value at time zero. (-=>) :: (b -> b) -> SF a b -> SF a b -- | Apply a function to the first input value at time zero. (>=-) :: (a -> a) -> SF a b -> SF a b -- | Precomposition with a pure function. (^>>) :: Arrow a => Box (b -> c) -> a c d -> a b d -- | Postcomposition with a pure function. (>>^) :: Arrow a => a b c -> Box (c -> d) -> a b d -- | Precomposition with a pure function (right-to-left variant). (<<^) :: Arrow a => a c d -> Box (b -> c) -> a b d -- | Postcomposition with a pure function (right-to-left variant). (^<<) :: Arrow a => Box (c -> d) -> a b c -> a b d -- | Left-to-right composition (>>>) :: forall k cat (a :: k) (b :: k) (c :: k). Category cat => cat a b -> cat b c -> cat a c infixr 1 >>> instance Control.Category.Category Rattus.Yampa.SF instance Rattus.Arrow.Arrow Rattus.Yampa.SF -- | Helper functions to convert streams and signal functions from Rattus -- into Haskell. module Rattus.ToHaskell -- | Turn a stream function into a state machine. runTransducer :: (Str a -> Str b) -> Trans a b -- | Turn a signal function into a state machine from inputs of type -- a and time (since last input) to output of type b. runSF :: SF a b -> Trans (a, Double) b -- | Turns a stream into a lazy infinite list. fromStr :: Str a -> [a] -- | Turns a lazy infinite list into a stream. toStr :: [a] -> Str a -- | A state machine that takes inputs of type a and produces -- output of type b. In addition to the output of type -- b the underlying function also returns the new state of the -- state machine. data Trans a b Trans :: (a -> (b, Trans a b)) -> Trans a b