1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
{-# OPTIONS_GHC -fglasgow-exts #-}
-----------------------------------------------------------------------------
-- |
-- Module : Control.Arrow.Transformer.Stream
-- Copyright : (c) Ross Paterson 2003
-- License : BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer : ross@soi.city.ac.uk
-- Stability : experimental
-- Portability : non-portable (multi-parameter type classes)
--
-- Arrow transformer lifting an arrow to streams.
module Control.Arrow.Transformer.Stream(
StreamArrow,
runStream,
StreamMap,
StreamMapST, runStreamST,
ArrowAddStream(..),
) where
import Control.Monad.ST
import Control.Arrow
import Control.Arrow.Internals
import Control.Arrow.Operations
import Control.Arrow.Transformer
import Data.Stream
-- | Arrows between streams.
--
-- /Note/: 'lift' is only a functor if '***' in the underlying arrow is.
newtype StreamArrow a b c = Str (a (Stream b) (Stream c))
instance Arrow a => Arrow (StreamArrow a) where
arr f = Str (arr (fmap f))
Str f >>> Str g = Str (f >>> g)
first (Str f) =
Str (arr unzipStream >>> first f >>> arr (uncurry zipStream))
genmap :: Arrow a => a b c -> a (Stream b) (Stream c)
genmap f = arr (\xs -> (shd xs, stl xs)) >>>
f *** genmap f >>> arr (uncurry Cons)
-- Caution: genmap is only a functor if *** for the base arrow is.
-- (For Kleisli arrows, that would mean a commutative monad.)
-- The same goes for the equivalent lift: it can be used to lift arrows,
-- but won't preserve composition unless *** does.
instance Arrow a => ArrowTransformer (StreamArrow) a where
lift f = Str (genmap f)
-- The following promotions follow directly from the arrow transformer.
instance ArrowZero a => ArrowZero (StreamArrow a) where
zeroArrow = lift zeroArrow
instance ArrowState s a => ArrowState s (StreamArrow a) where
fetch = lift fetch
store = lift store
instance ArrowWriter w a => ArrowWriter w (StreamArrow a) where
write = lift write
newWriter (Str f) = Str (newWriter f >>> arr strength)
where strength :: Functor w' => (w' a',b) -> w' (a',b)
strength (v, y) = fmap (\x -> (x, y)) v
-- liftings of standard classes
instance Arrow a => ArrowChoice (StreamArrow a) where
left (Str f) = Str ((arr getLeft >>> f) &&& arr id >>> arr replace)
where getLeft (Cons (Left x) xs) = Cons x (getLeft xs)
getLeft (Cons (Right _) xs) = getLeft xs
replace (~(Cons x xs), Cons (Left _) ys) =
Cons (Left x) (replace (xs, ys))
replace (xs, Cons (Right y) ys) =
Cons (Right y) (replace (xs, ys))
instance ArrowLoop a => ArrowLoop (StreamArrow a) where
loop (Str f) =
Str (loop (arr (uncurry zipStream) >>> f >>> arr unzipStream))
instance ArrowPlus a => ArrowPlus (StreamArrow a) where
Str f <+> Str g = Str (f <+> g)
-- I don't know of any other useful promotions.
-- (elimWriter can be promoted, but doesn't seem useful.)
-- Circuits
instance ArrowLoop a => ArrowCircuit (StreamArrow a) where
delay x = Str (arr (Cons x))
-- | Run a stream processor on a stream of inputs, obtaining a stream
-- of outputs.
--
-- Typical usage in arrow notation:
--
-- > proc p -> do
-- > ...
-- > ys <- (|runStream (\x -> ...)|) xs
--
-- Here @xs@ refers to the input stream and @x@ to individual
-- elements of that stream. @ys@ is bound to the output stream.
runStream :: ArrowLoop a => StreamArrow a (e,b) c -> a (e,Stream b) (Stream c)
runStream (Str f) = arr (\(e, xs) -> fmap (\x -> (e, x)) xs) >>> f
instance ArrowLoop a => ArrowAddStream (StreamArrow a) a where
liftStream = lift
elimStream = runStream
-- | Mappings of streams
type StreamMap = StreamArrow (->)
-- | In-place state updates.
--
-- /Note/: this is an arrow type, and 'lift' can be used to promote arrows
-- from @'Kleisli' ('ST' s)@: the resulting arrow updates the state for
-- each stream element in turn, and as long as the final state in not
-- required all is well. However, 'lift' does not preserve composition,
-- because this monad isn't commutative. In particular, a composition
-- of 'lift's of state transformers will not work, as the second will
-- require the final state of the first.
type StreamMapST s = StreamArrow (Kleisli (ST s))
-- | Encapsulate a local state.
runStreamST :: (forall s. StreamMapST s e c) -> StreamMap e c
runStreamST cf = Str $ \ input -> runST (let Str (Kleisli f) = cf in f input)
|