Catana 0.1 → 0.2
raw patch · 3 files changed
+134/−53 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Monad.Catana: more :: Catana i o a Bool
+ Control.Monad.Catana: parallelB :: Catana i o a a -> Catana i o b b -> Catana i o c (a, b)
+ Control.Monad.Catana: parallelE :: Catana i o a a -> Catana i o b b -> Catana i o c (Either a b)
+ Control.Monad.Catana: serial :: Catana io o a a -> Catana i io b b -> Catana i o c (Either a b)
- Control.Monad.Catana: Catana :: ([i] -> (CatanaIO i o a -> CatanaIO i o b) -> CatanaIO i o b) -> Catana i o b a
+ Control.Monad.Catana: Catana :: ((a -> Step i o b) -> Step i o b) -> Catana i o b a
- Control.Monad.Catana: evalCatana' :: Catana i o a a -> [i] -> (a, [o])
+ Control.Monad.Catana: evalCatana' :: Catana i o a a -> [i] -> (Maybe a, [o])
- Control.Monad.Catana: runCatana :: Catana i o b a -> [i] -> (CatanaIO i o a -> CatanaIO i o b) -> CatanaIO i o b
+ Control.Monad.Catana: runCatana :: Catana i o b a -> (a -> Step i o b) -> Step i o b
- Control.Monad.Catana: stop :: Catana i o () a
+ Control.Monad.Catana: stop :: b -> Catana i o b a
Files
- Catana.cabal +1/−1
- Control/Monad/Catana.hs +132/−51
- LICENSE +1/−1
Catana.cabal view
@@ -7,7 +7,7 @@ -- The package version. See the Haskell package versioning policy -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for -- standards guiding when and how versions should be incremented.-Version: 0.1+Version: 0.2 -- A short (one-line) description of the package. Synopsis: A monad for complex manipulation of a stream.
Control/Monad/Catana.hs view
@@ -1,6 +1,6 @@ {- | Module : Control.Monad.Catana-Copyright : (c) Dustin DeWeese 2011+Copyright : (c) Dustin DeWeese 2011-2012 License : BSD3 Maintainer : dustin.deweese@gmail.com Stability : experimental@@ -16,7 +16,7 @@ [Example type:] @'Catana' i o b a@ -The Catana monad represents computations that are both catamorphisms and anamorphisms; they both consume and produce values. In addition, the Catana monad represents the computation in continuation-passing style, allowing the continuations to be manipulated as is Control.Monad.Cont+The Catana monad represents computations that are both catamorphisms and anamorphisms; they both consume and produce values. In addition, the Catana monad represents the computation in continuation-passing style, and implements callCC. -} module Control.Monad.Catana (@@ -24,13 +24,14 @@ Catana(..), consume, top,--- consumeOnly, -- too dangerous push, produce, stop,- more, evalCatana,- evalCatana'+ evalCatana',+ parallelB,+ parallelE,+ serial -- * Example 1: Usage of the Catana monad -- $catanaExample1 ) where@@ -38,6 +39,8 @@ import Control.Applicative import Control.Monad import Control.Monad.Cont+import Data.Either+import Data.Maybe {- $catanaExample1 @@ -61,82 +64,160 @@ > evalCatana catanaExample1 [1..4] > -- result: [3.0,2.0,-1.0,0.5,1.0,7.0,12.0,0.0] ++An example using serial and parallel data flow:++>catanaExample2 = sq `serial` (ev `parallelB` od)+> where od = forever $ do+> x <- consume+> when (odd x) .+> produce $ x * 2+> ev = forever $ do+> x <- consume+> when (even x) .+> produce $ x + 3+> sq = forever $ do+> x <- consume+> produce x+> produce $ x ^ 2++> let l = 1 : evalCatana catanaExample2 l+> take 10 l+> -- result: [1,2,4,5,25,7,49,10,100,50]+ -} -data Catana i o b a = Catana { runCatana :: [i] -> (CatanaIO i o a -> CatanaIO i o b) -> CatanaIO i o b }-type CatanaIO i o a = (a, [i], [o] -> [o])+data Catana i o b a = Catana { runCatana :: (a -> Step i o b) -> Step i o b } +data Step i o a = Yield o (Step i o a)+ | Waiting (i -> Step i o a)+ | Done a+ instance Functor (Catana i o b) where- fmap f (Catana l) = Catana $ \i k ->- l i $ \(x, i', o') ->- k (f x, i', o')+ fmap f (Catana l) = Catana $ l . (. f) instance Applicative (Catana i o b) where- Catana fl <*> x = Catana $ \i k ->- fl i $ \(f, i', o1) ->- let (x', i'', o2) = runCatana (fmap f x) i' k- in (x', i'', o1 . o2)- pure x = Catana $ \i k -> k (x, i, id) + Catana fl <*> x = Catana $ \k ->+ fl $ \f ->+ runCatana (fmap f x) k+ pure x = Catana $ \k -> k x+ instance Monad (Catana i o b) where return = pure- Catana l >>= f = Catana $ \i k ->- l i $ \(x, i', o1) ->- let (x', i'', o2) = runCatana (f x) i' k- in (x', i'', o1 . o2)+ Catana l >>= f = Catana $ \k ->+ l $ \x ->+ runCatana (f x) k instance MonadCont (Catana i o b) where- callCC f = Catana $ \i k ->- let g x = Catana $ \i' _ -> k (x, i', id)- in runCatana (f g) i k+ callCC f = Catana $ \k -> runCatana (f $ Catana . const . k) k -- |Consumes an element from the input list, returning it -- If there is no more input, the chain of continuations ends -- immediately; no more computations will be processed consume :: Catana i o a i-consume = Catana f- where f (x : i) k = k (x, i, id)- f i k = (undefined, i, id)+consume = Catana Waiting -- |Returns the next input without consuming it top :: Catana i o a i-top = Catana f- where f i@(x : _) k = k (x, i, id)- f i k = (undefined, i, id)+top = Catana $ \k -> Waiting (\i -> feed i (k i)) --- |Consumes only the element satisfying p, leaving the other--- elements in the input list. This could cause space leaks if--- the input is never fully consumed-consumeOnly :: (i -> Bool) -> Catana i o a i-consumeOnly p = Catana f- where f i k | null b = (undefined, i, id)- | otherwise = k (head b, a ++ tail b, id)- where (a, b) = span (not . p) i+-- |Feeds an input into the next Waiting step+feed :: i -> Step i o a -> Step i o a+feed i (Yield o s) = Yield o (feed i s)+feed i (Waiting s) = s i+feed _ (Done x) = Done x -- |Stops computation, ending the continuation chain-stop :: Catana i o () a-stop = Catana $ \i k -> ((), i, id)---- |Tests for more input-more :: Catana i o a Bool-more = Catana f- where f [] k = k (False, [], id)- f i k = k (True, i, id)+stop :: b -> Catana i o b a+stop = Catana . const . Done -- |Pushes 'x' into the input push :: i -> Catana i o a ()-push x = Catana $ \i k -> k ((), x:i, id)+push x = Catana $ feed x . ($()) -- |Produces 'x' in the output produce :: o -> Catana i o a ()-produce x = Catana $ \i k -> k ((), i, (x:))+produce x = Catana $ Yield x . ($()) -- |Converts a Catana monad into a function over lists evalCatana :: Catana i o a a -> [i] -> [o]-evalCatana c i = o []- where (_, _, o) = runCatana c i id+evalCatana c = runSteps (runCatana c Done) +-- |Helper for evalCatana, runs the steps+runSteps :: Step i o a -> [i] -> [o]+runSteps (Yield o s) i = o : runSteps s i+runSteps (Waiting f) (i:is) = runSteps (f i) is+runSteps (Waiting _) [] = []+runSteps (Done x) _ = []+ -- |Evaluates a Catana monad over a list returning the result and output-evalCatana' :: Catana i o a a -> [i] -> (a, [o])-evalCatana' c i = (x, o [])- where (x, _, o) = runCatana c i id+evalCatana' :: Catana i o a a -> [i] -> (Maybe a, [o])+evalCatana' c i = (listToMaybe x, o)+ where (x, o) = partitionEithers $ runSteps' (runCatana c Done) i++-- |Helper for evalCatana', runs the steps+runSteps' :: Step i o a -> [i] -> [Either a o]+runSteps' (Yield o s) i = Right o : runSteps' s i+runSteps' (Waiting f) (i:is) = runSteps' (f i) is+runSteps' (Waiting _) [] = []+runSteps' (Done x) _ = [Left x]++-- |Helper for parallelB, combine steps to consume the same input at the same time, using k as the continuation+parStepsB :: Step i o a -> Step i o b -> ((a,b) -> Step i o c) -> Step i o c++-- Yield when possible+parStepsB (Yield oA sA) (Yield oB sB) k = Yield oA . Yield oB $ parStepsB sA sB k+parStepsB (Yield oA sA) sB k = Yield oA $ parStepsB sA sB k+parStepsB sA (Yield oB sB) k = Yield oB $ parStepsB sA sB k++-- Wait for input+parStepsB (Waiting fA) (Waiting fB) k = Waiting $ \i -> parStepsB (fA i) (fB i) k+parStepsB (Waiting fA) sB k = Waiting $ \i -> parStepsB (fA i) sB k+parStepsB sA (Waiting fB) k = Waiting $ \i -> parStepsB sA (fB i) k++-- Apply continuation to results+parStepsB (Done xA) (Done xB) k = k (xA, xB)++-- |Combine two monads to run in parallel, consuming the same input+parallelB :: Catana i o a a -> Catana i o b b -> Catana i o c (a, b)+parallelB a b = Catana $ parStepsB (runCatana a Done) (runCatana b Done)++-- |Helper for parallelB, combine steps to consume the same input at the same time, using k as the continuation+parStepsE :: Step i o a -> Step i o b -> (Either a b -> Step i o c) -> Step i o c++-- Yield when possible+parStepsE (Yield oA sA) (Yield oB sB) k = Yield oA . Yield oB $ parStepsE sA sB k+parStepsE (Yield oA sA) sB k = Yield oA $ parStepsE sA sB k+parStepsE sA (Yield oB sB) k = Yield oB $ parStepsE sA sB k++-- Apply continuation to result+parStepsE (Done xA) _ k = k (Left xA)+parStepsE _ (Done xB) k = k (Right xB)++-- Wait for input+parStepsE (Waiting fA) (Waiting fB) k = Waiting $ \i -> parStepsE (fA i) (fB i) k++-- |Combine two monads to run in parallel, consuming the same input, stopping when either of them finish.+parallelE :: Catana i o a a -> Catana i o b b -> Catana i o c (Either a b)+parallelE a b = Catana $ parStepsE (runCatana a Done) (runCatana b Done)++serSteps :: Step io o a -> Step i io b -> (Either a b -> Step i o c) -> Step i o c++-- Yield when possible+serSteps (Yield oA sA) sB k = Yield oA $ serSteps sA sB k++-- Apply continuation to results+serSteps (Done xA) _ k = k (Left xA)+serSteps _ (Done xB) k = k (Right xB)++-- Pass output from B to A+serSteps (Waiting fA) (Yield oB sB) k = serSteps (fA oB) sB k++-- Wait for input to B+serSteps sA (Waiting fB) k = Waiting $ \i -> serSteps sA (fB i) k++-- |Combine two monads to run in serial, the first consuming the output of the second+serial :: Catana io o a a -> Catana i io b b -> Catana i o c (Either a b)+serial a b = Catana $ serSteps (runCatana a Done) (runCatana b Done)+
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c)2011, Dustin DeWeese+Copyright (c)2011-2012, Dustin DeWeese All rights reserved.