{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

-- ------------------------------------------------------------

{- |
   Module     : Control.Arrow.IOStateListArrow
   Copyright  : Copyright (C) 2005-8 Uwe Schmidt
   License    : MIT

   Maintainer : Uwe Schmidt (uwe\@fh-wedel.de)
   Stability  : experimental
   Portability: portable

   Implementation of arrows with IO and a state

-}

-- ------------------------------------------------------------

module Control.Arrow.IOStateListArrow
    ( IOSLA(..)
    , liftSt
    , runSt
    )
where

import Prelude hiding (id, (.))

import Control.Category

import Control.Arrow
import Control.Arrow.ArrowExc
import Control.Arrow.ArrowIf
import Control.Arrow.ArrowIO
import Control.Arrow.ArrowList
import Control.Arrow.ArrowNF
import Control.Arrow.ArrowTree
import Control.Arrow.ArrowNavigatableTree
import Control.Arrow.ArrowState

import Control.DeepSeq
import Control.Exception                ( SomeException
                                        , try
                                        )
{-
import qualified Debug.Trace as T
-}
-- ------------------------------------------------------------

-- | list arrow combined with a state and the IO monad

newtype IOSLA s a b = IOSLA { forall s a b. IOSLA s a b -> s -> a -> IO (s, [b])
runIOSLA :: s -> a -> IO (s, [b]) }

instance Category (IOSLA s) where
    id :: forall a. IOSLA s a a
id                  = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s a
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [a
x])      -- don't defined id = arr id, this gives loops during optimization
    {-# INLINE id #-}

    IOSLA s -> b -> IO (s, [c])
g . :: forall b c a. IOSLA s b c -> IOSLA s a b -> IOSLA s a c
. IOSLA s -> a -> IO (s, [b])
f   = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s a
x -> do
                                           (s
s1, [b]
ys) <- s -> a -> IO (s, [b])
f s
s a
x
                                           s -> [b] -> IO (s, [c])
sequence' s
s1 [b]
ys
                                           where
                                           sequence' :: s -> [b] -> IO (s, [c])
sequence' s
s' []       = forall (m :: * -> *) a. Monad m => a -> m a
return (s
s', [])
                                           sequence' s
s' (b
x':[b]
xs') = do
                                                                   (s
s1', [c]
ys') <- s -> b -> IO (s, [c])
g s
s' b
x'
                                                                   (s
s2', [c]
zs') <- s -> [b] -> IO (s, [c])
sequence' s
s1' [b]
xs'
                                                                   forall (m :: * -> *) a. Monad m => a -> m a
return (s
s2', [c]
ys' forall a. [a] -> [a] -> [a]
++ [c]
zs')

instance Arrow (IOSLA s) where
    arr :: forall b c. (b -> c) -> IOSLA s b c
arr b -> c
f               = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [b -> c
f b
x])
    {-# INLINE arr #-}

    first :: forall b c d. IOSLA s b c -> IOSLA s (b, d) (c, d)
first (IOSLA s -> b -> IO (s, [c])
f)     = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s (b
x1, d
x2) -> do
                                                   (s
s', [c]
ys1) <- s -> b -> IO (s, [c])
f s
s b
x1
                                                   forall (m :: * -> *) a. Monad m => a -> m a
return (s
s', [ (c
y1, d
x2) | c
y1 <- [c]
ys1 ])

    -- just for efficiency
    second :: forall b c d. IOSLA s b c -> IOSLA s (d, b) (d, c)
second (IOSLA s -> b -> IO (s, [c])
g)    = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s (d
x1, b
x2) -> do
                                                  (s
s', [c]
ys2) <- s -> b -> IO (s, [c])
g s
s b
x2
                                                  forall (m :: * -> *) a. Monad m => a -> m a
return (s
s', [ (d
x1, c
y2) | c
y2 <- [c]
ys2 ])

    -- just for efficiency
    IOSLA s -> b -> IO (s, [c])
f *** :: forall b c b' c'.
IOSLA s b c -> IOSLA s b' c' -> IOSLA s (b, b') (c, c')
*** IOSLA s -> b' -> IO (s, [c'])
g = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s (b
x1, b'
x2) -> do
                                                   (s
s1, [c]
ys1) <- s -> b -> IO (s, [c])
f s
s  b
x1
                                                   (s
s2, [c']
ys2) <- s -> b' -> IO (s, [c'])
g s
s1 b'
x2
                                                   forall (m :: * -> *) a. Monad m => a -> m a
return (s
s2, [ (c
y1, c'
y2) | c
y1 <- [c]
ys1, c'
y2 <- [c']
ys2 ])

    -- just for efficiency
    IOSLA s -> b -> IO (s, [c])
f &&& :: forall b c c'. IOSLA s b c -> IOSLA s b c' -> IOSLA s b (c, c')
&&& IOSLA s -> b -> IO (s, [c'])
g = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s
s1, [c]
ys1) <- s -> b -> IO (s, [c])
f s
s  b
x
                                           (s
s2, [c']
ys2) <- s -> b -> IO (s, [c'])
g s
s1 b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s2, [ (c
y1, c'
y2) | c
y1 <- [c]
ys1, c'
y2 <- [c']
ys2 ])



instance ArrowZero (IOSLA s) where
    zeroArrow :: forall b c. IOSLA s b c
zeroArrow           = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s -> forall a b. a -> b -> a
const (forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, []))
    {-# INLINE zeroArrow #-}


instance ArrowPlus (IOSLA s) where
    IOSLA s -> b -> IO (s, [c])
f <+> :: forall b c. IOSLA s b c -> IOSLA s b c -> IOSLA s b c
<+> IOSLA s -> b -> IO (s, [c])
g = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s
s1, [c]
rs1) <- s -> b -> IO (s, [c])
f s
s  b
x
                                           (s
s2, [c]
rs2) <- s -> b -> IO (s, [c])
g s
s1 b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s2, [c]
rs1 forall a. [a] -> [a] -> [a]
++ [c]
rs2)

instance ArrowChoice (IOSLA s) where
    left :: forall b c d. IOSLA s b c -> IOSLA s (Either b d) (Either c d)
left (IOSLA s -> b -> IO (s, [c])
f)      = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
                                         (\ b
x -> do
                                                 (s
s1, [c]
y) <- s -> b -> IO (s, [c])
f s
s b
x
                                                 forall (m :: * -> *) a. Monad m => a -> m a
return (s
s1, forall a b. (a -> b) -> [a] -> [b]
map forall a b. a -> Either a b
Left [c]
y)
                                         )
                                         (\ d
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [forall a b. b -> Either a b
Right d
x]))

    right :: forall b c d. IOSLA s b c -> IOSLA s (Either d b) (Either d c)
right (IOSLA s -> b -> IO (s, [c])
f)     = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
                                         (\ d
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [forall a b. a -> Either a b
Left d
x]))
                                         (\ b
x -> do
                                                 (s
s1, [c]
y) <- s -> b -> IO (s, [c])
f s
s b
x
                                                 forall (m :: * -> *) a. Monad m => a -> m a
return (s
s1, forall a b. (a -> b) -> [a] -> [b]
map forall a b. b -> Either a b
Right [c]
y)
                                         )

instance ArrowApply (IOSLA s) where
    app :: forall b c. IOSLA s (IOSLA s b c, b) c
app                 = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s (IOSLA s -> b -> IO (s, [c])
f, b
x) -> s -> b -> IO (s, [c])
f s
s b
x
    {-# INLINE app #-}

instance ArrowList (IOSLA s) where
    arrL :: forall b c. (b -> [c]) -> IOSLA s b c
arrL b -> [c]
f              = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, (b -> [c]
f b
x))
    {-# INLINE arrL #-}
    arr2A :: forall b c d. (b -> IOSLA s c d) -> IOSLA s (b, c) d
arr2A b -> IOSLA s c d
f             = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s (b
x, c
y) -> forall s a b. IOSLA s a b -> s -> a -> IO (s, [b])
runIOSLA (b -> IOSLA s c d
f b
x) s
s c
y
    {-# INLINE arr2A #-}
    constA :: forall c b. c -> IOSLA s b c
constA c
c            = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s   -> forall a b. a -> b -> a
const (forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [c
c]))
    {-# INLINE constA #-}
    isA :: forall b. (b -> Bool) -> IOSLA s b b
isA b -> Bool
p               = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, if b -> Bool
p b
x then [b
x] else [])
    {-# INLINE isA #-}
    IOSLA s -> b -> IO (s, [c])
f >>. :: forall b c d. IOSLA s b c -> ([c] -> [d]) -> IOSLA s b d
>>. [c] -> [d]
g       = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s
s1, [c]
ys) <- s -> b -> IO (s, [c])
f s
s b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s1, [c] -> [d]
g [c]
ys)
    {-# INLINE (>>.) #-}

    -- just for efficency
    perform :: forall b c. IOSLA s b c -> IOSLA s b b
perform (IOSLA s -> b -> IO (s, [c])
f)   = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s
s1, [c]
_ys) <- s -> b -> IO (s, [c])
f s
s b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s1, [b
x])
    {-# INLINE perform #-}

instance ArrowIf (IOSLA s) where
    ifA :: forall b c d.
IOSLA s b c -> IOSLA s b d -> IOSLA s b d -> IOSLA s b d
ifA (IOSLA s -> b -> IO (s, [c])
p) IOSLA s b d
ta IOSLA s b d
ea = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s
s1, [c]
res) <- s -> b -> IO (s, [c])
p s
s b
x
                                           forall s a b. IOSLA s a b -> s -> a -> IO (s, [b])
runIOSLA ( if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [c]
res
                                                      then IOSLA s b d
ea
                                                      else IOSLA s b d
ta
                                                    ) s
s1 b
x

    (IOSLA s -> b -> IO (s, [c])
f) orElse :: forall b c. IOSLA s b c -> IOSLA s b c -> IOSLA s b c
`orElse` IOSLA s b c
g
                        = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           r :: (s, [c])
r@(s
s1, [c]
res) <- s -> b -> IO (s, [c])
f s
s b
x
                                           if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [c]
res
                                              then forall s a b. IOSLA s a b -> s -> a -> IO (s, [b])
runIOSLA IOSLA s b c
g s
s1 b
x
                                              else forall (m :: * -> *) a. Monad m => a -> m a
return (s, [c])
r


instance ArrowIO (IOSLA s) where
    arrIO :: forall b c. (b -> IO c) -> IOSLA s b c
arrIO b -> IO c
cmd           = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           c
res <- b -> IO c
cmd b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [c
res])
    {-# INLINE arrIO #-}

instance ArrowExc (IOSLA s) where
    tryA :: forall b c. IOSLA s b c -> IOSLA s b (Either SomeException c)
tryA IOSLA s b c
f              = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           Either SomeException (s, [c])
res <- forall a. IO a -> IO (Either SomeException a)
try' forall a b. (a -> b) -> a -> b
$ forall s a b. IOSLA s a b -> s -> a -> IO (s, [b])
runIOSLA IOSLA s b c
f s
s b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ case Either SomeException (s, [c])
res of
                                              Left   SomeException
er      -> (s
s,  [forall a b. a -> Either a b
Left SomeException
er])
                                              Right (s
s1, [c]
ys) -> (s
s1, [forall a b. b -> Either a b
Right c
x' | c
x' <- [c]
ys])
        where
        try'            :: IO a -> IO (Either SomeException a)
        try' :: forall a. IO a -> IO (Either SomeException a)
try'            = forall e a. Exception e => IO a -> IO (Either e a)
try

instance ArrowIOIf (IOSLA s) where
    isIOA :: forall b. (b -> IO Bool) -> IOSLA s b b
isIOA b -> IO Bool
p             = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           Bool
res <- b -> IO Bool
p b
x
                                           forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, if Bool
res then [b
x] else [])
    {-# INLINE isIOA #-}

instance ArrowState s (IOSLA s) where
    changeState :: forall b. (s -> b -> s) -> IOSLA s b b
changeState s -> b -> s
cf      = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> let s' :: s
s' = s -> b -> s
cf s
s b
x in forall (m :: * -> *) a. Monad m => a -> m a
return (seq :: forall a b. a -> b -> b
seq s
s' s
s', [b
x])
    {-# INLINE changeState #-}
    accessState :: forall b c. (s -> b -> c) -> IOSLA s b c
accessState s -> b -> c
af      = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> forall (m :: * -> *) a. Monad m => a -> m a
return (s
s, [s -> b -> c
af s
s b
x])
    {-# INLINE accessState #-}

-- ------------------------------------------------------------

-- |
-- lift the state of an IOSLA arrow to a state with an additional component.
--
-- This is uesful, when running predefined IO arrows, e.g. for document input,
-- in a context with a more complex state component.

liftSt          :: IOSLA s1 b c -> IOSLA (s1, s2) b c
liftSt :: forall s1 b c s2. IOSLA s1 b c -> IOSLA (s1, s2) b c
liftSt (IOSLA s1 -> b -> IO (s1, [c])
f)
    = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ (s1
s1, s2
s2) b
x -> do
                              (s1
s1', [c]
ys) <- s1 -> b -> IO (s1, [c])
f s1
s1 b
x
                              forall (m :: * -> *) a. Monad m => a -> m a
return ((s1
s1', s2
s2), [c]
ys)


-- |
-- run an arrow with augmented state in the context of a simple state arrow.
-- An initial value for the new state component is needed.
--
-- This is useful, when running an arrow with an extra environment component, e.g.
-- for namespace handling in XML.

runSt           :: s2 -> IOSLA (s1, s2) b c -> IOSLA s1 b c
runSt :: forall s2 s1 b c. s2 -> IOSLA (s1, s2) b c -> IOSLA s1 b c
runSt s2
s2 (IOSLA (s1, s2) -> b -> IO ((s1, s2), [c])
f)
    = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s1
s1 b
x -> do
                        ((s1
s1', s2
_s2'), [c]
ys) <- (s1, s2) -> b -> IO ((s1, s2), [c])
f (s1
s1, s2
s2) b
x
                        forall (m :: * -> *) a. Monad m => a -> m a
return (s1
s1', [c]
ys)

-- ------------------------------------------------------------

instance ArrowTree (IOSLA s)

instance ArrowNavigatableTree (IOSLA s)

instance ArrowNF (IOSLA s) where
    rnfA :: forall c b. NFData c => IOSLA s b c -> IOSLA s b c
rnfA (IOSLA s -> b -> IO (s, [c])
f)      = forall s a b. (s -> a -> IO (s, [b])) -> IOSLA s a b
IOSLA forall a b. (a -> b) -> a -> b
$ \ s
s b
x -> do
                                           (s, [c])
res <- s -> b -> IO (s, [c])
f s
s b
x
                                           ( -- T.trace "start rnfA for IOSLA" $
                                             forall a b. (a, b) -> b
snd (s, [c])
res
                                             )
                                             forall a b. NFData a => a -> b -> b
`deepseq`
                                              forall (m :: * -> *) a. Monad m => a -> m a
return ( -- T.trace "end rnfA for IOSLA" $
                                                       (s, [c])
res
                                                     )

instance ArrowWNF (IOSLA s)

-- ------------------------------------------------------------