{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} -- ------------------------------------------------------------ {- | Module : Control.Arrow.StateListArrow Copyright : Copyright (C) 2010 Uwe Schmidt License : MIT Maintainer : Uwe Schmidt (uwe\@fh-wedel.de) Stability : experimental Portability: portable Implementation of list arrows with a state -} -- ------------------------------------------------------------ module Control.Arrow.StateListArrow ( SLA(..) , fromSLA ) where import Prelude hiding (id, (.)) import Control.Category import Control.Arrow import Control.Arrow.ArrowIf import Control.Arrow.ArrowList import Control.Arrow.ArrowNF import Control.Arrow.ArrowState import Control.Arrow.ArrowTree import Control.Arrow.ArrowNavigatableTree import Control.DeepSeq -- ------------------------------------------------------------ -- | list arrow combined with a state newtype SLA s a b = SLA { runSLA :: s -> a -> (s, [b]) } instance Category (SLA s) where id = SLA $ \ s x -> (s, [x]) {-# INLINE id #-} SLA g . SLA f = SLA $ \ s x -> let ~(s1, ys) = f s x sequence' s' [] = (s', []) sequence' s' (x':xs') = let ~(s1', ys') = g s' x' ~(s2', zs') = sequence' s1' xs' in (s2', ys' ++ zs') in sequence' s1 ys instance Arrow (SLA s) where arr f = SLA $ \ s x -> (s, [f x]) {-# INLINE arr #-} first (SLA f) = SLA $ \ s ~(x1, x2) -> let ~(s', ys1) = f s x1 in (s', [ (y1, x2) | y1 <- ys1 ]) -- just for efficiency second (SLA g) = SLA $ \ s ~(x1, x2) -> let ~(s', ys2) = g s x2 in (s', [ (x1, y2) | y2 <- ys2 ]) -- just for efficiency SLA f *** SLA g = SLA $ \ s ~(x1, x2) -> let ~(s1, ys1) = f s x1 ~(s2, ys2) = g s1 x2 in (s2, [ (y1, y2) | y1 <- ys1, y2 <- ys2 ]) -- just for efficiency SLA f &&& SLA g = SLA $ \ s x -> let ~(s1, ys1) = f s x ~(s2, ys2) = g s1 x in (s2, [ (y1, y2) | y1 <- ys1, y2 <- ys2 ]) instance ArrowZero (SLA s) where zeroArrow = SLA $ \ s -> const (s, []) {-# INLINE zeroArrow #-} instance ArrowPlus (SLA s) where SLA f <+> SLA g = SLA $ \ s x -> let ~(s1, rs1) = f s x ~(s2, rs2) = g s1 x in (s2, rs1 ++ rs2) instance ArrowChoice (SLA s) where left (SLA f) = SLA $ \ s -> let lf x = (s1, map Left y) where ~(s1, y) = f s x rf x = (s, [Right x]) in either lf rf right (SLA f) = SLA $ \ s -> let lf x = (s, [Left x]) rf x = (s1, map Right y) where ~(s1, y) = f s x in either lf rf instance ArrowApply (SLA s) where app = SLA $ \ s (SLA f, x) -> f s x {-# INLINE app #-} instance ArrowList (SLA s) where arrL f = SLA $ \ s x -> (s, (f x)) {-# INLINE arrL #-} arr2A f = SLA $ \ s ~(x, y) -> runSLA (f x) s y {-# INLINE arr2A #-} constA c = SLA $ \ s -> const (s, [c]) {-# INLINE constA #-} isA p = SLA $ \ s x -> (s, if p x then [x] else []) {-# INLINE isA #-} SLA f >>. g = SLA $ \ s x -> let ~(s1, ys) = f s x in (s1, g ys) {-# INLINE (>>.) #-} -- just for efficency perform (SLA f) = SLA $ \ s x -> let ~(s1, _ys) = f s x in (s1, [x]) {-# INLINE perform #-} instance ArrowIf (SLA s) where ifA (SLA p) ta ea = SLA $ \ s x -> let ~(s1, res) = p s x in runSLA ( if null res then ea else ta ) s1 x (SLA f) `orElse` g = SLA $ \ s x -> let r@(s1, res) = f s x in if null res then runSLA g s1 x else r instance ArrowState s (SLA s) where changeState cf = SLA $ \ s x -> (cf s x, [x]) {-# INLINE changeState #-} accessState af = SLA $ \ s x -> (s, [af s x]) {-# INLINE accessState #-} instance ArrowTree (SLA s) instance ArrowNavigatableTree (SLA s) instance ArrowNF (SLA s) where rnfA (SLA f) = SLA $ \ s x -> let res = f s x in snd res `deepseq` res instance ArrowWNF (SLA s) -- ------------------------------------------------------------ -- | conversion of state list arrows into arbitray other -- list arrows. -- -- allows running a state list arrow within another arrow: -- -- example: -- -- > ... >>> fromSLA 0 (... setState ... getState ... ) >>> ... -- -- runs a state arrow with initial state 0 (e..g. an Int) within -- another arrow sequence fromSLA :: ArrowList a => s -> SLA s b c -> a b c fromSLA s f = arrL (snd . (runSLA f s)) {-# INLINE fromSLA #-} -- ------------------------------------------------------------