free-operational (empty) → 0.2.0.0
raw patch · 12 files changed
+723/−0 lines, 12 filesdep +QuickCheckdep +basedep +checkerssetup-changed
Dependencies added: QuickCheck, base, checkers, comonad-transformers, free, free-operational, kan-extensions, mtl, test-framework, test-framework-quickcheck2, transformers
Files
- Control/Alternative/Operational.hs +64/−0
- Control/Applicative/Operational.hs +195/−0
- Control/Monad/Operational.hs +104/−0
- Control/Monad/Operational/Simple.hs +53/−0
- Control/Monad/Trans/Operational.hs +87/−0
- Control/MonadPlus/Operational.hs +57/−0
- Control/Operational/Class.hs +10/−0
- Control/Operational/Instruction.hs +34/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- free-operational.cabal +74/−0
- tests/Properties.hs +13/−0
+ Control/Alternative/Operational.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | @operational@-style 'Alternative' programs. See+-- "Control.Applicative.Operational" for guidance on how to use this+-- module.+module Control.Alternative.Operational + ( module Control.Operational.Class+ , ProgramAlt(..)+ , interpretAlt+ , fromProgramAlt++ , ProgramViewAlt(..)+ , viewAlt+ ) where++import Control.Applicative+import qualified Control.Alternative.Free as Free+import Control.Alternative.Free hiding (Pure)+import Control.Operational.Class+import Control.Operational.Instruction+import Data.Functor.Yoneda.Contravariant++newtype ProgramAlt instr a =+ ProgramAlt { -- | Interpret the program as a free 'Alternative' ('Alt').+ toAlt :: Alt (Yoneda instr) a + } deriving (Functor, Applicative, Alternative)++instance Operational instr (ProgramAlt instr) where+ singleton = ProgramAlt . liftAlt . liftInstr++interpretAlt :: forall instr f a.+ Alternative f =>+ (forall x. instr x -> f x)+ -> ProgramAlt instr a + -> f a+interpretAlt evalI = runAlt (liftEvalI evalI) . toAlt++fromProgramAlt + :: (Operational instr f, Alternative f) => ProgramAlt instr a -> f a+fromProgramAlt = interpretAlt singleton++data ProgramViewAlt instr a where+ Pure :: a -> ProgramViewAlt instr a+ (:<**>) :: instr a+ -> ProgramViewAlt instr (a -> b) + -> ProgramViewAlt instr b+ Empty :: ProgramViewAlt instr a+ (:<|>) :: ProgramViewAlt instr a + -> ProgramViewAlt instr a+ -> ProgramViewAlt instr a++-- this is the same fixity as '<**>' and '<|>'; dunno why it's not infixr+infixl 4 :<**>+infixl 3 :<|>++viewAlt :: ProgramAlt instr a -> ProgramViewAlt instr a+viewAlt = viewAlt' . toAlt++viewAlt' :: Alt (Yoneda instr) a -> ProgramViewAlt instr a+viewAlt' (Free.Pure a) = Pure a+viewAlt' (Free.Ap (Yoneda f i) next) = i :<**> viewAlt' (fmap (.f) next)+viewAlt' (Free.Alt xs) = foldr (:<|>) Empty (map viewAlt' xs)
+ Control/Applicative/Operational.hs view
@@ -0,0 +1,195 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | 'Applicative' programs over an @operational@-style instruction+-- set, implemented on top of the 'Ap' free 'Applicative' type.+module Control.Applicative.Operational + ( module Control.Operational.Class+ , ProgramAp(..)+ , interpretAp+ , fromProgramAp++ , ProgramViewAp(..)+ , viewAp+ , compile++ , foldProgramViewAp+ , instructions+ , AnyInstr(..)+ ) where++import Control.Applicative+import Control.Applicative.Free (Ap, runAp, liftAp)+import qualified Control.Applicative.Free as Free+import Control.Operational.Class+import Control.Operational.Instruction+import Data.Functor.Yoneda.Contravariant+++-- | An 'Applicative' program over instruction set @instr@. This is+-- modeled after the 'Program' type from @operational@+-- (<http://hackage.haskell.org/package/operational>), but this one is+-- an 'Applicative', not a 'Monad'. This makes it less powerful, but+-- in exchange for the sacrificed power 'ProgramAp' is suceptible to+-- much stronger static analysis.+--+-- For examples of this (though applied to free applicatives), see:+--+-- * <http://gergo.erdi.hu/blog/2012-12-01-static_analysis_with_applicatives/>+-- +-- * <http://paolocapriotti.com/blog/2013/04/03/free-applicative-functors/>+newtype ProgramAp instr a = + ProgramAp { -- | Interpret a 'ProgramAp' as a free applicative ('Ap').+ toAp :: Ap (Yoneda instr) a + } deriving (Functor, Applicative)++instance Operational instr (ProgramAp instr) where+ singleton = ProgramAp . liftAp . liftInstr++-- | Evaluate a 'ProgramAp' by interpreting each instruction as an+-- 'Applicative' action. Example @Reader@ implementation:+--+-- > type Reader r a = ProgramAp (ReaderI r) a+-- >+-- > data ReaderI r a where+-- > Ask :: ReaderI r r+-- > +-- > ask :: Reader r r+-- > ask = singleton Ask+-- > +-- > runReader :: forall r a. Reader r a -> r -> a+-- > runReader = interpretAp evalI+-- > where evalI :: forall a. ReaderI r a -> r -> a+-- > evalI Ask = id+interpretAp :: forall instr f a.+ Applicative f =>+ (forall x. instr x -> f x)+ -> ProgramAp instr a + -> f a+interpretAp evalI = runAp (liftEvalI evalI) . toAp++-- | Lift a 'ProgramAp' into any other 'Operational' program type that+-- is at least as strong as 'Applicative'; e.g., lift an applicative+-- program into a monadic one. Note that not all applicatives are+-- monads, so a lifted program may \"lose\" some of the+-- interpretations that the original could be given.+fromProgramAp+ :: (Operational instr f, Applicative f) => ProgramAp instr a -> f a+fromProgramAp = interpretAp singleton+++-- | A friendly concrete tree view type for 'ProgramAp'. Unlike the+-- ':>>=' constructor in the 'ProgramView' type of+-- "Control.Monad.Operational", whose second data member is a function+-- that consumes an instruction result to generate the rest of the+-- program, our ':<**>' constructor exposes the rest of program+-- immediately.+--+-- Note that the 'ProgramViewAp' type normalizes the program into a+-- different ordering and bracketing than the applicative '<*>'+-- operator does. The ':<**>' constructor is an analogue of @'<**>'+-- :: Applicative f => f a -> f (a -> b) -> f b@ from+-- "Control.Applicative". The normalization means that you get a+-- list-like structure with instructions as the elements (in the same+-- order as their effects) and 'Pure' as the terminator.+--+-- A static analysis example, based on Capriotti and Kaposi (2013,+-- <http://paolocapriotti.com/blog/2013/04/03/free-applicative-functors/>):+--+-- > {-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables #-}+-- >+-- > import Control.Operational.Applicative+-- > +-- > data FileSystemI a where+-- > Read :: FilePath -> FileSystemI String +-- > Write :: FilePath -> String -> FileSystemI ()+-- > +-- > -- | Count how many file accesses a program does.+-- > count :: ProgramAp FileSystemI a -> Int+-- > count = count' . viewAp+-- > where count' :: forall x. ProgramViewAp FileSystemI x -> Int+-- > count' (Pure _) = 0+-- > count' (_ :<**> k) = succ (count' k)+-- +-- Or actually, just this:+--+-- > count :: ProgramAp FileSystemI a -> Int+-- > count = length . instructions+--+-- You can also use the 'ProgramViewAp' to interpret the program, in+-- the style of the @operational@ package. Example implementation of+-- a simple terminal language in this style:+--+-- > data TermI a where+-- > Say :: String -> TermI ()+-- > Get :: TermI String+-- > +-- > say :: String -> ProgramAp TermI ()+-- > say = singleton . Say+-- > +-- > get :: ProgramAp TermI String+-- > get = singleton Get+-- > +-- > prompt :: String -> ProgramAp TermI String+-- > prompt str = say str *> get+-- > +-- > runTerm :: ProgramAp TermI a -> IO a+-- > runTerm = eval . viewAp+-- > where eval :: forall x. ProgramViewAp TermI x -> IO x+-- > eval (Pure a) = pure a+-- > eval (Say str :<**> k) = putStr str <**> eval k+-- > eval (Get :<**> k) = getLine <**> eval k +-- >+-- > example :: ProgramAp TermI (String, String)+-- > example = (,) <$> prompt "First question: " <*> prompt "Second question: "+-- > +-- > -- example = Say "First question: " :<**> (Get :<**> (Say "Second question: " :<**> (Get :<**> Pure (\_ a _ b -> (a, b)))))+--+-- But as a general rule, 'interpretAp' makes for shorter, less+-- repetitive, fooler-proof interpreters:+--+-- > runTerm :: ProgramAp TermI a -> IO a+-- > runTerm = interpretAp evalI+-- > where evalI :: forall x. TermI x -> IO x+-- > evalI (Say str) = putStr str+-- > evalI Get = getLine+--+data ProgramViewAp instr a where+ Pure :: a -> ProgramViewAp instr a+ (:<**>) :: instr a+ -> ProgramViewAp instr (a -> b) + -> ProgramViewAp instr b++-- this is the same fixity as '<**>'; dunno why it's not infixr+infixl 4 :<**> ++-- | Materialize a 'ProgramAp' as a concrete tree. Note that+-- 'ProgramAp''s 'Functor' and 'Applicative' instances normalize their+-- programs, so the view term may not look like the code that created+-- it. Instructions however will appear in the order that their+-- effects should happen, from left to right.+viewAp :: ProgramAp instr a -> ProgramViewAp instr a+viewAp = viewAp' . toAp++viewAp' :: Ap (Yoneda instr) a -> ProgramViewAp instr a+viewAp' (Free.Pure a) = Pure a+viewAp' (Free.Ap (Yoneda f i) next) = i :<**> viewAp' (fmap (.f) next)++-- | Compile a 'ProgramViewAp' back into a 'ProgramAp'.+compile :: ProgramViewAp instr a -> ProgramAp instr a+compile (Pure f) = pure f+compile (instr :<**> k) = singleton instr <**> compile k+++foldProgramViewAp :: (forall x. instr x -> r -> r) + -> r+ -> ProgramViewAp instr a+ -> r+foldProgramViewAp k z (Pure _) = z+foldProgramViewAp k z (i :<**> is) = k i (foldProgramViewAp k z is)++instructions :: ProgramAp instr a -> [AnyInstr instr]+instructions = foldProgramViewAp (\i -> (AnyInstr i:)) [] . viewAp++data AnyInstr instr = forall a. AnyInstr (instr a)
+ Control/Monad/Operational.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | A reconstruction of the @operational@ package in terms of the+-- 'FreeT' monad transformer.+--+-- This module is meant to be a drop-in replacement for its+-- counterpart in the @operational@ package. Some of the+-- implementation choices reflect that:+--+-- * @'Program' instr@ and @'ProgramView' instr@ are type synonyms for+-- @'ProgramT' instr m@ and @'ProgramViewT' instr m@, just as in+-- @operational@. If you don't care for that,+-- "Control.Monad.Operational.Simple" implements them directly in+-- terms of 'Free'.+--+-- The 'ProgramT' and 'ProgramViewT' types and operations are+-- reexported from "Control.Monad.Trans.Operational".+module Control.Monad.Operational+ ( module Control.Operational.Class+ , module Control.Monad.Trans.Operational+ , Program+ , toFree+ , fromProgram+ , liftProgram+ , interpret+ , interpretWithMonad+ , ProgramView+ , view+ ) where++import Control.Applicative+import Control.Monad+import Control.Monad.Free (Free)+import qualified Control.Monad.Free as Free+import Control.Monad.Identity+import Control.Monad.Trans+import Control.Monad.Trans.Identity+import Control.Monad.Trans.Free (FreeT)+import qualified Control.Monad.Trans.Free as FreeT+import Control.Monad.Trans.Operational+import Control.Operational.Class+import Control.Operational.Instruction+import Data.Functor.Yoneda.Contravariant+++-- | Drop-in replacement for @operational@'s type synonym.+type Program instr = ProgramT instr Identity++-- | The 'Free' monad action for a 'Program'.+toFree :: Program instr a -> Free (Yoneda instr) a+toFree = freeT2Free . toFreeT+ where+ freeT2Free :: Functor f => FreeT f Identity a -> Free f a+ freeT2Free = adjust . runIdentity . FreeT.runFreeT+ where adjust (FreeT.Pure a) = Free.Pure a+ adjust (FreeT.Free fb) = Free.Free $ fmap freeT2Free fb++-- | Lift a 'Program' into any 'Operational' type at least as strong+-- as 'Monad'.+fromProgram+ :: (Operational instr m, Functor m, Monad m) => Program instr a -> m a+fromProgram = interpret singleton++-- | Lift a 'Program' into a 'ProgramT'. Really the same as+-- 'fromProgram', but with a more restricted type; this function is a+-- drop-in replacement for the eponymous function in @operational@.+liftProgram :: Monad m => Program instr a -> ProgramT instr m a+liftProgram = fromProgram+++-- | Interpret a 'Program' by interpreting each instruction as a+-- monadic action. Unlike 'interpretWithMonad', this soes not use+-- 'view' nor 'ProgramView'.+--+-- This function is not a drop-in replacement for 'interpretWithMonad'+-- because it has an extra @Functor m@ constraint.+interpret :: forall m instr a. (Functor m, Monad m) =>+ (forall x. instr x -> m x)+ -> Program instr a+ -> m a+interpret evalI = runIdentityT . interpretTM (lift . evalI) . liftProgram++-- | Drop-in replacement for the eponymous function in the+-- @operational@ package. This is like 'interpret' but with a+-- slightly broader type, and the same implementation as in+-- @operational@ (in terms of 'view').+interpretWithMonad :: Monad m =>+ (forall x. instr x -> m x)+ -> Program instr a+ -> m a+interpretWithMonad evalI = eval . view+ where eval (Return a) = return a+ eval (i :>>= k) = evalI i >>= interpretWithMonad evalI . k+++-- | Drop-in replacement for @operational@'s eponymous type synonym.+type ProgramView instr = ProgramViewT instr Identity++-- | Drop-in replacement for @operational@'s function.+view :: Program instr a -> ProgramView instr a+view = runIdentity . viewT+
+ Control/Monad/Operational/Simple.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | A simpler, non-transformer version of this package's+-- "Control.Monad.Operational"\'s 'Program' type, using 'Free'+-- directly.+module Control.Monad.Operational.Simple + ( module Control.Operational.Class+ , Program(..)+ , interpret+ , fromProgram+ , ProgramView(..)+ , view+ ) where++import Control.Applicative+import Control.Monad.Free+import Control.Operational.Class+import Control.Operational.Instruction+import Data.Functor.Yoneda.Contravariant+++newtype Program instr a = + Program { -- | Intepret the program as a 'Free' monad.+ toFree :: Free (Yoneda instr) a + } deriving (Functor, Applicative, Monad)++instance Operational instr (Program instr) where+ singleton = Program . liftF . liftInstr++-- | Interpret a 'Program' by translating each instruction to a+-- 'Monad' action. Does not use 'view'.+interpret :: forall m instr a. (Functor m, Monad m) => + (forall x. instr x -> m x)+ -> Program instr a+ -> m a+interpret evalI = retract . hoistFree (liftEvalI evalI) . toFree++-- | Lift a 'Program' to any 'Operational' instance at least as+-- powerful as 'Monad'.+fromProgram+ :: (Operational instr m, Functor m, Monad m) => Program instr a -> m a+fromProgram = interpret singleton++data ProgramView instr a where+ Return :: a -> ProgramView instr a+ (:>>=) :: instr a -> (a -> Program instr b) -> ProgramView instr b++view :: Program instr a -> ProgramView instr a+view = eval . toFree + where eval (Pure a) = Return a+ eval (Free (Yoneda f i)) = i :>>= (Program . f)
+ Control/Monad/Trans/Operational.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Control.Monad.Trans.Operational+ ( ProgramT(..)+ , interpretT+ , interpretTM+ , interpretM+ , ProgramViewT(..)+ , viewT+ ) where++import Control.Applicative+import Control.Monad+import Control.Monad.Trans+import Control.Monad.Trans.Free+import Control.Operational.Class+import Control.Operational.Instruction+import Data.Functor.Yoneda.Contravariant+++newtype ProgramT instr m a = + ProgramT { toFreeT :: FreeT (Yoneda instr) m a + } deriving (Functor, Applicative, Monad, MonadTrans)++instance Monad m => Operational instr (ProgramT instr m) where+ singleton = ProgramT . liftF . liftInstr++-- | Given an intepretation of @instr x@ as actions over a given monad+-- transformer @t@ (transforming over an arbitrary monad @m@),+-- interpret @'ProgramT' instr@ as a monad transformer @t@. Read that+-- sentence and the type carefully: the instruction interpretation can+-- pick its choice of @t@ but not @m@.+interpretT+ :: forall t m instr a. + (MonadTrans t, Functor (t m), Monad (t m), Functor m, Monad m) => + (forall n x. + (Functor n, Monad n) =>+ instr x -> t n x) -- ^ interpret @instr@ over a transformer+ -- @t@ and any wrapped monad @n@.+ -> ProgramT instr m a + -> t m a+interpretT evalI = retractT . transFreeT evalF . toFreeT+ where evalF :: forall m x.+ (Functor (t m), Monad (t m), Functor m, Monad m) => + Yoneda instr x -> t m x+ evalF (Yoneda f i) = fmap f (evalI i)++retractT :: (MonadTrans t, Functor (t m), Monad (t m), Monad m) => + FreeT (t m) m a -> t m a+retractT = retract . hoistFreeT lift++retract :: Monad m => FreeT m m a -> m a+retract prog = do fab <- runFreeT prog+ case fab of+ Pure a -> return a+ Free fb -> join $ liftM retract fb++-- | Given an intepretation of @instr x@ as actions over a given+-- transformed monad @t m@, interpret @'ProgramT' instr@ as a+-- transformed monad @t m@. Read that sentence and the type+-- carefully: the instruction interpretation can pick its choice of+-- both @t@ and @m@.+interpretTM+ :: (MonadTrans t, Functor (t m), Monad (t m), Monad m) => + (forall x. instr x -> t m x) -- ^ interpret @instr@ over @t m@+ -> ProgramT instr m a+ -> t m a+interpretTM evalI = retractT . transFreeT (liftEvalI evalI) . toFreeT++interpretM :: (Functor m, Monad m) => + (forall x. instr x -> m x) -> ProgramT instr m a -> m a+interpretM evalI = retract . transFreeT (liftEvalI evalI) . toFreeT+++data ProgramViewT instr m a where+ Return :: a -> ProgramViewT instr m a+ (:>>=) :: instr a -> (a -> ProgramT instr m b) -> ProgramViewT instr m b++infixl 1 :>>=++viewT :: Monad m => ProgramT instr m a -> m (ProgramViewT instr m a)+viewT = liftM eval . runFreeT . toFreeT+ where eval (Pure a) = Return a+ eval (Free (Yoneda f i)) = i :>>= ProgramT . f+
+ Control/MonadPlus/Operational.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | @operational@-style programs for 'MonadPlus'. See the+-- documentation for "Control.Applicative.Operational" and+-- "Control.Monad.Operational" for guidance on how to use this module.+module Control.MonadPlus.Operational+ ( module Control.Operational.Class+ , ProgramP(..)+ , interpretP+ , fromProgramP+ + , ProgramViewP(..)+ , view+ ) where++import Control.Applicative+import Control.Monad+import Control.MonadPlus.Free+import Control.Operational.Class+import Data.Functor.Yoneda.Contravariant++newtype ProgramP instr a = + ProgramP { -- | Interpret the program as a free 'MonadPlus'.+ toFree :: Free (Yoneda instr) a + } deriving (Functor, Applicative, Alternative, Monad, MonadPlus)++instance Operational instr (ProgramP instr) where+ singleton = ProgramP . liftF . liftYoneda++interpretP :: forall m instr a. (Functor m, MonadPlus m) => + (forall x. instr x -> m x)+ -> ProgramP instr a+ -> m a+interpretP evalI = retract . hoistFree evalF . toFree+ where evalF :: forall x. Yoneda instr x -> m x+ evalF (Yoneda f i) = fmap f (evalI i)++fromProgramP+ :: (Operational instr m, Functor m, MonadPlus m) => ProgramP instr a -> m a+fromProgramP = interpretP singleton+++data ProgramViewP instr a where+ Return :: a -> ProgramViewP instr a+ (:>>=) :: instr a -> (a -> ProgramP instr b) -> ProgramViewP instr b+ MEmpty :: ProgramViewP instr a+ MPlus :: ProgramViewP instr a+ -> ProgramViewP instr a+ -> ProgramViewP instr a++view :: ProgramP instr a -> ProgramViewP instr a+view = eval . toFree + where eval (Pure a) = Return a+ eval (Free (Yoneda f i)) = i :>>= (ProgramP . f)+ eval (Plus mas) = foldr MPlus MEmpty (map eval mas)
+ Control/Operational/Class.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}++module Control.Operational.Class + ( Operational(..)+ ) where++-- | The class of operational programs. +class Operational instr p | p -> instr where+ -- | Make a program out of an instruction.+ singleton :: instr a -> p a
+ Control/Operational/Instruction.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE Rank2Types #-}++-- | Utility functions for working with instructions and instruction sets.+--+-- The "Data.Functor.Coproduct" module is very useful with instruction+-- sets, so this module reexports it. The 'Coproduct' type can be+-- used to take the union of two instruction sets, and the 'coproduct'+-- function can be used to construct an instruction evaluation for+-- such an union. So if we have these two instruction evaluations:+--+-- > evalI :: forall x. instr x -> f x+-- > evalI' :: forall x. instr' x -> f x +--+-- then their 'coproduct' is an evaluation for the union of the+-- instruction sets:+-- +-- > coproduct evalI evalI' :: forall x. (Coproduct instr instr' x) -> f x+module Control.Operational.Instruction + ( module Data.Functor.Coproduct+ , liftEvalI+ , liftInstr+ ) where++import Data.Functor.Coproduct+import Data.Functor.Yoneda.Contravariant++-- | Lift an operational instruction evaluator into a free 'Functor'+-- evaluator.+liftEvalI :: Functor f => (forall x. instr x -> f x) -> Yoneda instr a -> f a+liftEvalI evalI (Yoneda f i) = fmap f (evalI i) ++liftInstr :: instr a -> Yoneda instr a+liftInstr = liftYoneda+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Luis Casillas++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Luis Casillas nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ free-operational.cabal view
@@ -0,0 +1,74 @@+name: free-operational+category: Control+version: 0.2.0.0+build-type: Simple+cabal-version: >=1.8+synopsis: Operational Applicative, Alternative, Monad and MonadPlus, built with free types.++description: + A reimplementation of the @operational@ package+ (<http://hackage.haskell.org/package/operational>) using free monads + (from <http://hackage.haskell.org/package/free>). This implements+ ideas discussed here:+ .+ * <http://stackoverflow.com/questions/14263363/is-operational-really-isomorphic-to-a-free-monad>+ .+ * <http://www.reddit.com/r/haskell/comments/17a33g/free_functors_the_reason_free_and_operational_are/>+ .+ To understand the basic concepts you can do no better than read+ Heinrich Apfelmus' @operational@ tutorial:+ .+ * <http://apfelmus.nfshost.com/articles/operational-monad.html>+ .+ In addition to that, this package supplies @operational@-style+ modules for 'Applicative', 'Alternative' and 'MonadPlus'.+ 'Applicative' and 'Alternative' programs easily admit of static+ analysis. See these references for discussion and examples:+ .+ * <http://gergo.erdi.hu/blog/2012-12-01-static_analysis_with_applicatives/> (discussion: <http://www.reddit.com/r/haskell/comments/143wpd/static_analysis_with_applicatives/>)+ .+ * <http://paolocapriotti.com/blog/2013/04/03/free-applicative-functors/> (discussion: <http://www.reddit.com/r/haskell/comments/1bnql3/free_applicative_functors_icfp_submission/>)+ .+ See "Control.Applicative.Operational" for the bulk of the documentation.++license: BSD3+license-file: LICENSE+author: Luis Casillas+maintainer: luis@casillas.org+copyright: 2013 Luis Casillas+bug-reports: https://github.com/sacundim/free-operational/issues+source-repository head+ type: git+ location: https://github.com/sacundim/free-operational+++test-suite tests+ type: exitcode-stdio-1.0+ hs-source-dirs: tests+ Main-is: Properties.hs+ build-depends: base ==4.*,+ mtl >=2.1,+ transformers >=0.3,+ free-operational >=0.2,+ test-framework >=0.8,+ test-framework-quickcheck2 >=0.3, + QuickCheck >=2.4,+ checkers >=0.3++library+ exposed-modules: Control.Operational.Class,+ Control.Operational.Instruction,+ Control.Applicative.Operational,+ Control.Alternative.Operational,+ Control.Monad.Operational,+ Control.Monad.Operational.Simple,+ Control.Monad.Trans.Operational,+ Control.MonadPlus.Operational+ + build-depends: base == 4.*,+ transformers >=0.3,+ mtl >=2.1,+ free >=3.3,+ comonad-transformers >=3.0,+ kan-extensions >=3.1+
+ tests/Properties.hs view
@@ -0,0 +1,13 @@+module Main+ ( main+ ) where++import qualified Properties.Applicative as Ap++import Test.Framework (Test, defaultMain, testGroup)++main :: IO ()+main = defaultMain tests++tests :: [Test]+tests = [ testGroup "applicative" Ap.tests ]