packages feed

transient 0.3 → 0.4.0

raw patch · 8 files changed

+374/−214 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Transient.Base: delSData :: (MonadState EventF m, Typeable a) => a -> m ()
- Transient.Base: setSData :: (MonadState EventF m, Typeable a) => a -> m ()
- Transient.EVars: delEVar :: EVar a -> TransIO ()
- Transient.Internals: (!>) :: Show a => b -> a -> b
- Transient.Internals: delSData :: (MonadState EventF m, Typeable a) => a -> m ()
- Transient.Internals: delSessionData :: (Typeable * a, MonadState EventF m) => a -> m ()
- Transient.Internals: infixr 0 !>
- Transient.Internals: setSData :: (MonadState EventF m, Typeable a) => a -> m ()
+ Transient.Base: (**>) :: TransIO a -> TransIO b -> TransIO b
+ Transient.Base: (<|) :: TransIO a -> TransIO b -> TransIO a
+ Transient.Base: delData :: (MonadState EventF m, Typeable a) => a -> m ()
+ Transient.Base: exit :: a -> TransIO a
+ Transient.EVars: Finish :: (EVar FinishReason) -> Finish
+ Transient.EVars: checkFinalize :: StreamData a -> TransIO a
+ Transient.EVars: cleanEVar :: EVar a -> TransIO ()
+ Transient.EVars: data Finish
+ Transient.EVars: finish :: FinishReason -> TransIO ()
+ Transient.EVars: initFinish :: TransIO Finish
+ Transient.EVars: killOnFinish :: TransIO b -> TransIO b
+ Transient.EVars: lastWriteEVar :: MonadIO m => EVar t -> t -> m ()
+ Transient.EVars: onFinish :: (FinishReason -> TransIO ()) -> TransIO ()
+ Transient.EVars: type FinishReason = Maybe SomeException
+ Transient.EVars: unFinish :: TransIO ()
+ Transient.Internals: (**>) :: TransIO a -> TransIO b -> TransIO b
+ Transient.Internals: (<|) :: TransIO a -> TransIO b -> TransIO a
+ Transient.Internals: IDNUM :: Int -> IDNUM
+ Transient.Internals: delData :: (MonadState EventF m, Typeable a) => a -> m ()
+ Transient.Internals: instance GHC.Show.Show Transient.Internals.IDNUM
+ Transient.Internals: newtype IDNUM
+ Transient.Internals: readWithErr :: (Typeable * a, Read a) => [Char] -> IO [(a, String)]
+ Transient.Internals: readsPrec' :: (Typeable * a, Read a) => t -> [Char] -> [(a, String)]
+ Transient.Internals: runCont' :: EventF -> IO (Maybe a, EventF)
+ Transient.Internals: runTransState :: EventF -> TransIO x -> IO (Maybe x, EventF)
+ Transient.Internals: showThreads :: TransIO empty
- Transient.Base: input :: (Typeable a, Read a) => (a -> Bool) -> TransIO a
+ Transient.Base: input :: (Typeable a, Read a, Show a) => (a -> Bool) -> String -> TransIO a
- Transient.Base: oneThread :: TransientIO a -> TransientIO a
+ Transient.Base: oneThread :: TransIO a -> TransientIO a
- Transient.Base: stop :: Alternative m => m a
+ Transient.Base: stop :: Alternative m => m stop
- Transient.EVars: EVar :: Int -> (TChan (StreamData a)) -> EVar a
+ Transient.EVars: EVar :: Int -> (TVar (Int, Int)) -> (TChan (StreamData a)) -> EVar a
- Transient.EVars: newEVar :: TransientIO (EVar a)
+ Transient.EVars: newEVar :: TransIO (EVar a)
- Transient.Internals: compose :: (Monad f, Alternative f) => [a1 -> f a1] -> a1 -> f a
+ Transient.Internals: compose :: (Alternative f, Monad f) => [t -> f t] -> t -> f a
- Transient.Internals: getLine' :: (Read a, Typeable * a) => (a -> Bool) -> IO a
+ Transient.Internals: getLine' :: (Typeable * a, Read a) => (a -> Bool) -> IO a
- Transient.Internals: infixr 1 <***
+ Transient.Internals: infixr 1 <**
- Transient.Internals: input :: (Typeable a, Read a) => (a -> Bool) -> TransIO a
+ Transient.Internals: input :: (Typeable a, Read a, Show a) => (a -> Bool) -> String -> TransIO a
- Transient.Internals: killChildren :: EventF -> IO ()
+ Transient.Internals: killChildren :: TVar [EventF] -> IO ()
- Transient.Internals: oneThread :: TransientIO a -> TransientIO a
+ Transient.Internals: oneThread :: TransIO a -> TransientIO a
- Transient.Internals: reads1 :: (Typeable * a, Read a) => String -> [(a, String)]
+ Transient.Internals: reads1 :: (Typeable * a, Read a) => [Char] -> [(a, String)]
- Transient.Internals: stop :: Alternative m => m a
+ Transient.Internals: stop :: Alternative m => m stop
- Transient.Internals: waitQSemB :: (Num a, Ord a) => IORef a -> IO Bool
+ Transient.Internals: waitQSemB :: (Ord a, Num a) => IORef a -> IO Bool

Files

src/Transient/Backtrack.hs view
@@ -20,7 +20,7 @@ -- | assures that backtracking will not go further back
 undoCut :: TransientIO ()
 undoCut= Transient $ do
-     delSData $ Backtrack False []
+     delData $ Backtrack False []
      return $ Just ()
 
 -- | the secod parameter will be executed when backtracking
src/Transient/Base.hs view
@@ -16,18 +16,20 @@ 
 TransIO(..), TransientIO
 ,keep, keep', stop
-,option, input
+,option, input, exit
 ,async,waitEvents, spawn, parallel
 ,react
 
-,setData,setSData,getData,getSData,delSData
+,setData,getData,getSData,delData
 
 , threads,addThreads, freeThreads, hookedThreads,oneThread, killChilds
 
-, (<**),(<***)
+, (**>), (<**),(<***), (<|)
 
 , StreamData(..)
-,genId)  where
--- /show
+,genId)
+
+where
+
 
 import    Transient.Internals
src/Transient/EVars.hs view
@@ -2,21 +2,24 @@ module Transient.EVars where
 
 import Transient.Base
-import Transient.Internals(onNothing, EventF)
+import Transient.Internals(runTransState,onNothing, EventF(..), killChildren)
 import qualified Data.Map as M
 import Data.Typeable
 
 import Control.Concurrent
 import Control.Applicative
 import Control.Concurrent.STM
-import Control.Monad.State
+import Control.Monad.IO.Class
+import Control.Exception(SomeException)
+
 import Data.List(nub)
+import Control.Monad.State
 
---newtype EVars= EVars  (IORef (M.Map Int [EventF]))  deriving Typeable
 
-data EVar a= EVar Int  (TChan (StreamData a)) deriving  Typeable
 
+data EVar a= EVar Int (TVar (Int,Int))  (TChan (StreamData a)) deriving  Typeable
 
+
 -- | creates an EVar.
 --
 -- Evars are event vars. `writeEVar` trigger the execution of all the continuations associated to the  `readEVar` of this variable
@@ -36,32 +39,121 @@ -- see https://www.fpcomplete.com/user/agocorona/publish-subscribe-variables-transient-effects-v
 --
 
-newEVar ::  TransientIO (EVar a)
+newEVar ::  TransIO (EVar a)
 newEVar  = Transient $ do
    id <- genId
+   rn <- liftIO $ newTVarIO (0,0)
    ref <-liftIO  newTChanIO
-   return . Just $ EVar id  ref
+   return . Just $ EVar id  rn ref
 
 -- | delete al the subscriptions for an evar.
-delEVar :: EVar a -> TransIO ()
-delEVar (EVar id  ref1)= liftIO $ atomically $ writeTChan  ref1 SDone
+cleanEVar :: EVar a -> TransIO ()
+cleanEVar (EVar id rn ref1)= liftIO $ atomically $ do
+    writeTChan  ref1 SDone
+    writeTVar rn (0,0)
 
 -- | read the EVar. It only succeed when the EVar is being updated
 -- The continuation gets registered to be executed whenever the variable is updated.
--- if readEVar is in any kind of loop, since each continuation is different, this will register
--- again the continuation. The effect is that the continuation will be executed multiple times
--- To avoid multiple registrations, use `unsubscribe`
-readEVar :: EVar a -> TransIO a
-readEVar (EVar id  ref1)= do
-     r <- parallel $ atomically $ readTChan ref1     -- !> "READEVAR"
+--
+-- if readEVar is re-executed in any kind of loop, since each continuation is different, this will register
+-- again. The effect is that the continuation will be executed multiple times
+-- To avoid multiple registrations, use `cleanEVar`
+readEVar (EVar id rn ref1)= do
+     liftIO $ atomically $ readTVar rn >>= \(n,n') -> writeTVar rn $ (n+1,n'+1)
+     r <- parallel $ atomically $ do
+                r <- peekTChan ref1
+----                return ()               !> "peekTChan executed"
+                (n,n') <- readTVar rn  -- !> "readtvar rn"
+--                return ()              !> ("rn",n)
+                if n'> 1 then do
+                           writeTVar rn (n,n'-1)
+                           return r
+                         else do
+                           readTChan ref1
+                           writeTVar rn (n,n)
+                           return r
+
      case r of
         SDone -> empty
         SMore x -> return x
         SLast x -> return x
-        SError e -> error $ show e
+        SError e -> do
+            liftIO . atomically $ readTVar rn >>= \(n,n') -> writeTVar rn $ (n-1,n'-1)
+            error $ "readEVar: "++ show e
 
 -- |  update the EVar and execute all readEVar blocks with "last in-first out" priority
-writeEVar (EVar id  ref1) x= liftIO $ atomically $ writeTChan  ref1 $ SMore x
+--
+writeEVar (EVar id rn ref1) x= liftIO $ atomically $ do
+       writeTChan  ref1 $ SMore x
 
 
+-- | write the EVar and drop all the `readEVar` handlers.
+--
+-- It is like a combination of `writeEVar` and `cleanEVar`
+lastWriteEVar (EVar id rn ref1) x= liftIO $ atomically $ do
+       writeTChan  ref1 $ SLast x
 
+
+-- Finalization
+
+
+type FinishReason= Maybe SomeException
+
+-- | trigger finish when the stream data return SDone
+checkFinalize v=
+           case v of
+              SDone ->  finish Nothing >> stop
+              SLast x ->  return x
+              SError e -> liftIO ( print e) >> finish Nothing >> stop
+              SMore x -> return x
+
+
+
+data Finish= Finish (EVar FinishReason) deriving Typeable
+
+-- | initialize the event variable for finalization.
+-- all the following computations in different threads will share it
+initFinish :: TransIO Finish
+initFinish= do
+      fin <-  newEVar
+      let f = Finish fin
+      setData  f
+      return  f
+
+
+onFinish :: (FinishReason ->TransIO ()) -> TransIO ()
+onFinish  close=  do
+
+                               Finish finish <- getSData <|> initFinish
+                               e <- readEVar finish
+                               close e  -- !!> "CLOSE"
+                               stop
+                         <|>
+                           return ()
+
+
+
+-- | trigger the event, so this closes all the resources
+finish :: FinishReason -> TransIO ()
+finish e= do
+    liftIO $ putStr  "finish: " >> print e
+    Finish finish <- getSData <|> initFinish
+    lastWriteEVar finish e
+
+-- | deregister all the finalization actions.
+-- A initFinish is needed to register actions again
+unFinish= do
+    Finish fin <- getSData
+    cleanEVar fin    -- !!> "DELEVAR"
+   <|> return ()   -- !!> "NOT DELEVAR"
+
+
+killOnFinish comp=   do
+
+   chs <- liftIO $ newTVarIO []
+   onFinish $ const $ do
+
+      liftIO $ killChildren chs   -- !> "killOnFinish event"
+   r <- comp
+   modify $ \ s -> s{children= chs}
+   return r
src/Transient/Indeterminism.hs view
@@ -98,7 +98,7 @@ -- It works monitoring the solutions found and the number of active threads.
 -- If the first parameter is 0, collect will return all the results
 collect ::  Int -> TransIO a -> TransIO [a]
-collect n = collect' n 0.01 0
+collect n = collect' n 0.1 0
 
 -- | search also between two time intervals. If the first interval has passed and there is no result,
 --it stops.
@@ -131,7 +131,7 @@ 
           th <- liftIO $ myThreadId   -- !> "KILL"
           stnow <-  get
-          liftIO $ killChildren st
+          liftIO . killChildren $ children st
           liftIO $ hangThread st stnow
           return  xs
 
src/Transient/Internals.hs view
@@ -39,11 +39,11 @@ import           Data.List
 import           Data.IORef
 import           System.Environment
-
-{-# INLINE (!>) #-}
-(!>) :: Show a => b -> a -> b
-(!>) x y=   trace (show y) x
-infixr 0 !>
+import           System.IO (hFlush,stdout)
+--{-# INLINE (!>) #-}
+--(!>) :: Show a => b -> a -> b
+--(!>) x y=   trace (show y) x
+--infixr 0 !>
 
 
 data TransIO  x = Transient  {runTrans :: StateT EventF IO (Maybe x)}
@@ -85,10 +85,10 @@       put s'
       return $ Just a
 
-type StateIO= StateT EventF  IO
-
+type StateIO= StateT EventF IO
 
 
+-- | run the transient computation with a blank state
 runTransient :: TransIO x -> IO (Maybe x, EventF)
 runTransient t= do
   th <- myThreadId
@@ -98,19 +98,22 @@ 
   runStateT (runTrans t) eventf0
 
-
-
+-- | run the transient computation with an state
+runTransState st x = runStateT (runTrans x) st
 
 -- | get the continuation context: closure, continuation, state, child threads etc
 getCont :: TransIO EventF
 getCont = Transient $ Just <$> get
 
--- | run the closure and the continuation context
+-- | run the closure and the continuation using the state data of the calling thread
 runCont :: EventF -> StateIO (Maybe a)
 runCont (EventF _ _ x fs _ _  _ _  _ _ _)= runTrans $ do
-      r <- (unsafeCoerce x)
-      (compose fs r)
+      r <- unsafeCoerce x
+      compose fs r
 
+-- | run the closure and the continuation using his own state data
+runCont' cont= runStateT (runCont cont) cont
+
 -- | warning: radiactive untyped stuff. handle with care
 getContinuations :: StateIO [a -> TransIO b]
 getContinuations= do
@@ -160,6 +163,9 @@      x <- mx
      return $ f x
 
+-- to set the identifier number...
+newtype IDNUM = IDNUM Int deriving Show
+
 instance Applicative TransIO where
   pure a  = Transient . return $ Just a
 
@@ -167,7 +173,6 @@          rf <- liftIO $ newIORef (Nothing,[])
          rg <- liftIO $ newIORef (Nothing,[])   -- !> "NEWIOREF"
 
-
          fs  <- getContinuations
 
          let
@@ -177,18 +182,17 @@ 
              appf k = Transient $  do
                    Log rec _ full <- getData `onNothing` return (Log False [] [])
-                   liftIO $ writeIORef rf  (Just k,full)
+                   liftIO $ writeIORef rf  (Just k,full)       --  !> "APPF"
                    (x, full2)<- liftIO $ readIORef rg
                    when (hasWait full2) $
                         let full'= head full2: full
                         in setData $ Log rec full' full'
 
-
                    return $ Just k <*> x
 
              appg x = Transient $  do
                    Log rec _ full <- getData `onNothing` return (Log False [] [])
-                   liftIO $ writeIORef rg $ (Just x, full)
+                   liftIO $ writeIORef rg (Just x, full)       -- !> "APPG"
                    (k,full1) <- liftIO $ readIORef rf
                    when (hasWait  full) $
                         let full'= head full: full1
@@ -200,11 +204,13 @@ 
          k <- runTrans f    -- !> "RUN f"
          was <- getData `onNothing` return NoRemote
-         when (was == WasParallel) $  setData NoRemote                                    -- !>  ("was=",was)
+         when (was == WasParallel) $  setData NoRemote
 
          Log recovery _ full <- getData `onNothing` return (Log False [] [])
 
-         if was== WasRemote  || (not recovery && was == NoRemote  && isNothing k)
+
+
+         if was== WasRemote  || (not recovery && was == NoRemote  && isNothing k ) -- !>  ("was,recovery,isNothing=",was,recovery, isNothing k))
          -- if the first operand was a remote request
          -- (so this node is not master and hasn't to execute the whole expression)
          -- or it was not an asyncronous term (a normal term without async or parallel
@@ -215,9 +221,11 @@            else do
              liftIO $ writeIORef rf  (k,full)
 
-             mfdata <- gets mfData
-             seq <- gets mfSequence
 
+--             mfdata <- gets mfData
+             n <- gets mfSequence
+             setData $ IDNUM n
+
              setContinuation g appg fs
 
              x <- runTrans g             --  !> "RUN g"
@@ -230,8 +238,17 @@        modify $ \(EventF eff _ f _ a b c d parent children g1) ->
                EventF eff Nothing f fs a b c d parent children g1
 
+readWithErr line=
+     let [(v,left)] = readsPrec 0 line
+     in (v   `seq` return [(v,left)])
+                    `catch` (\(e::SomeException) ->
+                      error ("read error of " ++ show( typeOf v) ++ " in: "++ line))
 
 
+readsPrec' _= unsafePerformIO . readWithErr
+
+
+
 -- | dynamic serializable data for logging
 data IDynamic= IDyns String | forall a.(Read a, Show a,Typeable a) => IDynamic a
 
@@ -240,7 +257,7 @@   show (IDyns s)= show s
 
 instance Read IDynamic where
-  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec n str
+  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec' n str
 
 
 type Recover= Bool
@@ -254,13 +271,7 @@   empty = Transient $ return  Nothing
   (<|>) = mplus
 
---  Transient f <|> Transient g= Transient $ do
---         k <-   f
---         x <-   g
---         return $ k <|> x
 
-
-
 data RemoteStatus=   WasRemote | WasParallel | NoRemote deriving (Typeable, Eq, Show)
 
 instance MonadPlus TransIO where
@@ -268,22 +279,33 @@     mplus  x y=  Transient $ do
          mx <- runTrans x                -- !!> "RUNTRANS11111"
          was <- getData `onNothing` return NoRemote
-         if was== WasRemote              -- !!> "check wasremote"
-           then return Nothing           --  !> was
-           else case mx of
-             Nothing -> runTrans y      --  !!> "RUNTRANS22222"
-             justx -> return justx
+         if was== WasRemote              -- !> was
+           then return Nothing
+           else
+                 case mx of
+                     Nothing -> runTrans y      --  !!> "RUNTRANS22222"
+                     justx -> return justx
 
 -- | a sinonym of empty that can be used in a monadic expression. it stop the
--- computation
-stop :: Alternative m => m a
+-- computation and execute the next alternative computation (composed with `<|>`)
+stop :: Alternative m => m stop
 stop= empty
 
-infixr 1  <**  ,  <***
 
--- | forces the execution of the second operand even if the first stop. Return the first result (experimental)
-(<**) :: TransIO a -> TransIO b -> TransIO a
-(<**) ma mb= Transient $ do
+-- | executes the second operand even if the frist return empty.
+-- A normal imperative (monadic) sequence uses the operator (>>) which in the Transient monad does not
+--- execute the next operand if the previous one return empty.
+(**>) :: TransIO a -> TransIO b -> TransIO b
+(**>) x y=  Transient $ do
+          runTrans x
+          runTrans y
+
+infixr 1  <***  ,  <**, **>
+
+-- | forces the execution of the second operand even if the first stop. Return the first result. The second
+-- operand is executed also when internal events happens in the first operand and it returns something
+(<***) :: TransIO a -> TransIO b -> TransIO a
+(<***) ma mb= Transient $ do
               fs  <- getContinuations
               setContinuation ma (\x -> mb >> return x)  fs
               a <- runTrans ma
@@ -291,20 +313,47 @@               restoreStack fs
               return  a
 
-atEnd= (<**)
+atEnd= (<***)
 
--- | forces the execution of the second operand  if the first fails only if the first operand
--- is executed normally, that is , it is not a reexecution consequence of an internal event on it.
+-- | forces the execution of the second operand even if the first stop. It does not execute
+-- the second operand as result of internal events occuring in the first operand.
 -- Return the first result
-(<***) :: TransIO a -> TransIO b -> TransIO a
-(<***) ma mb= Transient $ do
+(<**) :: TransIO a -> TransIO b -> TransIO a
+(<**) ma mb= Transient $ do
               a <- runTrans ma    -- !> "ma"
               runTrans  mb        -- !> "mb"
               return a
 
 
-atEnd' = (<***)
+atEnd' = (<**)
 
+
+
+-- | when the first operand is an asynchronous operation, the second operand is executed once (one single time)
+-- when the first completes his first asyncronous operation.
+--
+-- This is useful for spawning asynchronous or distributed tasks that are singletons and that should start
+-- when the first one is set up.
+--
+-- for example a streaming where the event receivers are acivated before the senders.
+
+(<|) :: TransIO a -> TransIO b -> TransIO a
+(<|)  ma mb =  Transient $ do
+          fs  <- getContinuations
+          ref <- liftIO $ newIORef False
+          setContinuation ma (cont ref )  fs
+          r <- runTrans ma
+          restoreStack fs
+          return  r
+    where
+    cont ref x= Transient $ do
+          n <- liftIO $ readIORef ref
+          if  n == True
+            then  return $ Just x
+            else do liftIO $ writeIORef ref True
+                    runTrans mb
+                    return $ Just x
+
 instance Monoid a => Monoid (TransIO a) where
   mappend x y = mappend <$> x <*> y
   mempty= return mempty
@@ -344,7 +393,7 @@ 
 instance Monad TransIO where
 
-      return x = Transient $ return $ Just x
+      return  = pure
 
       x >>= f  = Transient $ do
 --            effects <- gets effects -- liftIO $ readIORef refEventCont
@@ -377,9 +426,9 @@    modify $ \s -> s{maxThread = msem} -- restore it
    return r
 
--- | delete all the previous childs generated by the expressions and continue execution
+-- | delete all the previous childs generated by the expression taken as parameter and continue execution
 -- of the current thread.
-oneThread :: TransientIO a -> TransientIO a
+oneThread :: TransIO a -> TransientIO a
 oneThread comp=  do
    chs <- liftIO $ newTVarIO []
    r <-  comp
@@ -387,8 +436,27 @@    killChilds
    return r
 
+showThreads :: TransIO empty
+showThreads= do
+   st' <- gets (fromJust . parent)
+   liftIO $ showTree 0 st'
+   stop
+   where
+   toplevel st =
+      case parent st of
+        Nothing ->  st
+        Just p -> toplevel p
 
+   showThreads' n rchs= do
+      chs <- atomically $ readTVar rchs
+      mapM_ (showTree n) chs
 
+   showTree n ch=  do
+         putStr $ take n $ repeat  ' '
+         print $ threadId ch
+         showThreads' (n+4) $ children ch
+
+
 -- | add n threads to the limit of threads. If there is no limit, it set it
 addThreads' :: Int -> TransIO ()
 addThreads' n= Transient $ do
@@ -415,7 +483,7 @@ --    Nothing -> return Nothing
 
 
--- | The threads generated in the process passed as parameter will not be killed.
+-- | The threads generated in the process passed as parameter will not be killed by `kill*` primitives
 freeThreads :: TransIO a -> TransIO a
 freeThreads proc= Transient $ do
      st <- get
@@ -434,11 +502,11 @@      modify $ \st -> st{freeTh= freeTh st}
      return r
 
--- | kill all the child processes
+-- | kill all the child threads of the current thread
 killChilds :: TransientIO()
 killChilds= Transient $  do
    cont <- get
-   liftIO $  killChildren cont
+   liftIO $  killChildren $ children cont
    return $ Just ()
 
 -- * extensible state: session data management
@@ -463,6 +531,14 @@ --
 -- >  getSData <|> error "no data"
 --
+-- To have the same semantics and guarantees than `get`, use a default value:
+--
+-- > getInt= getSData <|> return (0 :: Int)
+--
+-- The default value (0 in this case) has the same role than the initial value in a state monad.
+-- The difference is that you can define as many `get` as you need for all your data types.
+--
+-- To distingish two data with the same types, use newtype definitions.
 getSData ::  Typeable a => TransIO  a
 getSData= Transient getData
 
@@ -476,16 +552,13 @@ setData  x=
   let t= typeOf x in  modify $ \st -> st{mfData= M.insert  t (unsafeCoerce x) (mfData st)}
 
--- | a shorter name for setData
-setSData ::  (MonadState EventF m, Typeable a) => a -> m ()
-setSData = setData
 
-delSessionData x=
+delData :: ( MonadState EventF m,Typeable a) => a -> m ()
+delData x=
   modify $ \st -> st{mfData= M.delete (typeOf x ) (mfData st)}
 
-delSData :: ( MonadState EventF m,Typeable a) => a -> m ()
-delSData= delSessionData
 
+
 --withSData ::  ( MonadState EventF m,Typeable a) => (Maybe a -> a) -> m ()
 --withSData f= modify $ \st -> st{mfData=
 --    let dat = mfData st
@@ -528,31 +601,41 @@ -- previous events
 waitEvents ::   IO b -> TransIO b
 waitEvents io= do
-   SMore r <- parallel (SMore <$> io)
-   return r
+   mr <- parallel (SMore <$> io)
+   case mr of
+     SMore x -> return x
+     SError e -> throw e
 
+
 -- Multithreaded version of `waitEvents` that do not kill the computations spawned by previous events
 waitEvents' ::   IO b -> TransIO b
 waitEvents' io= do
-   SMore r <- parallel (SMore <$> io)
-   return r
+   mr <- parallel (SMore <$> io)
+   case mr of
+     SMore x -> return x
+     SError e -> throw e
 
 -- | variant of `parallel` that execute the IO computation once, and kill the previous child threads
 async  ::  IO b -> TransIO b
 async io= do
-   SLast r <- parallel  (SLast <$>io)
-   return r
+   mr <- parallel  (SLast <$>io)
+   case mr of
+     SLast x -> return x
+     SError e -> throw e
 
 -- | variant that spawn free threads. Since there is no thread control, this is faster
 spawn ::  IO b -> TransIO b
 spawn io= freeThreads $ do
-   SMore r <- parallel (SMore <$>io)
-   return r
+   mr <- parallel (SMore <$>io)
+   case mr of
+     SMore x -> return x
+     SError e -> throw e
 
 
 
 
 
+
 -- |  return empty to the current thread, in new thread, execute the IO action,
 -- this IO action modify an internal buffer. then, executes the closure where `parallel` is located
 -- In this new execution, since the buffer is filled, `parallel` return the content of this buffer.
@@ -577,7 +660,9 @@         return $ unsafeCoerce j
      Nothing -> do
         liftIO $ loop cont ioaction
-        setData WasParallel
+        was <- getData `onNothing` return NoRemote
+        when (was /= WasRemote) $ setData WasParallel
+
         return Nothing
 
 
@@ -595,7 +680,7 @@ 
       -- execute the IO computation and then the closure-continuation
       loop'= forkMaybe False cont $ do
-         mdat <- threadDelay 0 >> rec
+         mdat <- threadDelay 0 >> rec `catch` \(e :: SomeException) -> return $ SError e
          case mdat of
              se@(SError _) ->  iocont se
              SDone ->          iocont SDone
@@ -604,7 +689,6 @@              more@(SMore _) -> do
                   forkMaybe False cont $ iocont more
                   loop'
-
   loop'
   return ()
   where
@@ -628,9 +712,9 @@                          case me of -- !> "THREAD END" of
                           Left  e -> do
                              when (fromException e /= Just ThreadKilled)$ liftIO $ print e
-                             killChildren  cont  -- !!> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
+                             killChildren $ children cont          -- !> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
 
-                          Right _ ->  when(not $ freeTh cont') $ do -- if was not a free thread
+                          Right _ ->  when(not $ freeTh cont')  $ do -- if was not a free thread
                              --  if parent is alive
                              --  then remove himself from the parent list (with free)
                              --  and pass his active children to his parent
@@ -638,7 +722,7 @@                              th <- myThreadId
                              mparent <- free th cont
                              return ()
-
+                               -- pass the active children to the parent
 --                             case mparent of
 --                              Nothing  ->  return()
 --                              Just parent -> atomically $ do
@@ -659,8 +743,7 @@ 
 forkFinally1 :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
 forkFinally1 action and_then =
-  mask $ \restore ->
-    forkIO $ try (restore action) >>= and_then
+  mask $ \restore ->  forkIO $ try (restore action) >>= and_then
 
 free th env= do
   if isNothing $ parent env
@@ -692,10 +775,9 @@        writeTVar headpths $  child:ths   -- !!>  "thread added: "++ show (threadId child)
 
 -- | kill  all the child threads associated with the continuation context
-killChildren cont  = do
+killChildren childs  = do
 
      forkIO $ do
-        let childs= children cont
         ths <- atomically $ do
            ths <- readTVar childs
            writeTVar childs []
@@ -711,12 +793,15 @@ type EventSetter eventdata response= (eventdata ->  IO response) -> IO ()
 type ToReturn  response=  IO response
 
--- | deinvert an event handler. The first parameter is the event handler setter to be
+-- | deinvert an event handler.
+--
+-- The first parameter is the setter of the event handler  to be
 -- deinverted. Usually it is the primitive provided by a framework to set an event handler
 --
--- the second is the value to return to the event handler
--- it configures the event handler by calling the first parameter, that set the event
--- handler, with the current continuation
+-- the second parameter is the value to return to the event handler. Usually it is `return()`
+--
+-- it configures the event handler by calling the setter of the event
+-- handler with the current continuation
 react
   :: Typeable eventdata
   => EventSetter eventdata response
@@ -724,22 +809,37 @@   -> TransIO eventdata
 react setHandler iob= Transient $ do
         cont    <- get
-        mEvData <- getData
-        case mEvData of
+        case event cont of
           Nothing -> do
             liftIO $ setHandler $ \dat ->do
-              runStateT (setData dat >> runCont cont) cont
+              runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat}
               iob
-            setSData WasParallel
+            was <- getData `onNothing` return NoRemote
+            when (was /= WasRemote) $ setData WasParallel
             return Nothing
-          Just dat -> do
-             delSessionData dat
-             return (Just  dat)
 
+          j@(Just _) -> do
+            put cont{event=Nothing}
+            return $ unsafeCoerce j
 
+--          Just dat -> do
+--             delData dat
+--             return (Just  dat)
 
 
+--    case event cont of
+--     Nothing -> do
+--        liftIO $ loop cont ioaction
+--        was <- getData `onNothing` return NoRemote
+--        when (was /= WasRemote) $ setData WasParallel
+--
+--        return Nothing
+--     j@(Just _) -> do
+--        put cont{event=Nothing}
+--        return $ unsafeCoerce j
 
+
+
 -- * non-blocking keyboard input
 
 getLineRef= unsafePerformIO $ newTVarIO Nothing
@@ -763,8 +863,10 @@ -- | validates an input entered in the keyboard in non blocking mode. non blocking means that
 -- the user can enter also anything else to activate other option
 -- unlike `option`, wich watch continuously, input only wait for one valid response
-input :: (Typeable a, Read a) => (a -> Bool) -> TransIO a
-input cond= Transient . liftIO . atomically $ do
+input :: (Typeable a, Read a,Show a) => (a -> Bool) -> String -> TransIO a
+input cond prompt= Transient . liftIO $do
+   putStr prompt >> hFlush stdout
+   atomically $ do
        mr <- readTVar getLineRef
        case mr of
          Nothing -> retry
@@ -772,6 +874,7 @@             case reads1 r  of
             (s,_):_ -> if cond s  --  !> show (cond s)
                      then do
+                       unsafeIOToSTM $ print s
                        writeTVar  getLineRef Nothing -- !>"match"
                        return $ Just s
 
@@ -795,12 +898,12 @@             _ -> retry
 
 reads1 s=x where
-      x= if typeOf(typeOfr x) == typeOf "" then unsafeCoerce[(s,"")] else readsPrec 0 s
+      x= if typeOf(typeOfr x) == typeOf "" then unsafeCoerce[(s,"")] else readsPrec' 0 s
       typeOfr :: [(a,String)] ->  a
       typeOfr  = undefined
 
 inputLoop=  do
-    putStrLn "Press end to exit"
+--    putStrLn "Press end to exit"
     inputLoop'  -- !> "started inputLoop"
     where
 
@@ -812,20 +915,27 @@ processLine r= do
 --   when (r=="end") $ atomically $ writeTVar rexit ()
    let rs = breakSlash [] r
-   mapM_ (\ r -> if (r=="end") then exit' $ Left "terminated by user" else do
-                    threadDelay 1000
-                    atomically . writeTVar  getLineRef $ Just r) rs
+   mapM_ (\ r ->  -- if (r=="end") then exit' $ Left "terminated by user" else
+                 do
+                    threadDelay 100000
+                    atomically . writeTVar  getLineRef $ Just r ) rs
 
+
     where
     breakSlash :: [String] -> String -> [String]
+    breakSlash [] ""= [""]
     breakSlash s ""= s
+    breakSlash res ('\"':s)=
+      let (r,rest) = span(/= '\"') s
+      in breakSlash (res++[r]) $ tail1 rest
+
     breakSlash res s=
       let (r,rest) = span(/= '/') s
       in breakSlash (res++[r]) $ tail1 rest
-      where
-      tail1 []=[]
-      tail1 x= tail x
 
+    tail1 []=[]
+    tail1 x= tail x
+
 {-# NOINLINE rexit #-}
 rexit= unsafePerformIO $ newEmptyMVar
 
@@ -837,21 +947,36 @@       Right (Just r) -> return r
       Left msg -> error msg
 
--- | keep the main thread running, initiate the asynchronous keyboard input and execute
--- the transient computation. It also read a slash separated list of string that are interpreted by
+-- | keep the main thread running, initiate the non blocking keyboard input and execute
+-- the transient computation.
+--
+-- It also read a slash-separated list of string that are read by
 -- `option` and `input` as if they were entered by the keyboard
+--
+-- >  foo  -p  options/to/be/read/by/option/and/input
+--
 keep :: TransIO a -> IO a
 keep mx = do
-   forkIO inputLoop
    forkIO $ do
-           runTransient $  mx >> liftIO (putMVar rexit  $ Right Nothing) -- to avoid takeMVar in a infinite loop
+           liftIO $ putMVar rexit  $ Right Nothing
+           runTransient $ do
+               (async inputLoop
+                       <|> (option "end" "exit" >> exit' (Left "terminated by user"))
+                       <|> return ())
+
+
+               mx
+               liftIO (putMVar rexit  $ Right Nothing) -- to avoid "takeMVar blocked in a infinite loop" error
            return ()
-   threadDelay 100000
+   threadDelay 10000
    args <- getArgs
-   let path = filter (\arg -> arg !! 0 == '/') args
-   when (not (null path)) $ do
-        putStr "Executing: " >> print (head path)
-        processLine $  head path
+   let mindex =  findIndex (\o ->  o == "-p" || o == "--path" ) args
+   when (isJust mindex) $ do
+        let i= fromJust mindex +1
+        when (length  args >= i) $ do
+          let path= args !! i
+          putStr "Executing: " >> print  path
+          processLine  path
    stay
 
 -- | same than `keep`but do not initiate the asynchronous keyboard input.
src/Transient/Logged.hs view
@@ -17,19 +17,19 @@ import Data.Typeable
 import Unsafe.Coerce
 import Transient.Base
-import Transient.Internals(onNothing,IDynamic(..),Log(..),LogElem(..),RemoteStatus(..))
+import Transient.Internals(onNothing,IDynamic(..),Log(..),LogElem(..),RemoteStatus(..),StateIO)
 import Control.Applicative
 import Control.Monad.IO.Class
-
+import Data.IORef
 
 
 class (Show a, Read a,Typeable a) => Loggable a
 instance (Show a, Read a,Typeable a) => Loggable a
 
 fromIDyn :: (Read a, Show a, Typeable a) => IDynamic -> a
-fromIDyn (IDynamic x)= unsafeCoerce x
+fromIDyn (IDynamic x)=r where r= unsafeCoerce x     -- !> "coerce" ++ " to type "++ show (typeOf r)
 
-fromIDyn (IDyns s)=r where r= read s  -- !!> "read " ++ s ++ "to type "++ show (typeOf r)
+fromIDyn (IDyns s)=r `seq`r where r= read s         -- !> "read " ++ s ++ " to type "++ show (typeOf r)
 
 toIDyn x= IDynamic x
 
@@ -62,53 +62,43 @@ logged mx =  Transient $ do
    Log recover rs full <- getData `onNothing` return ( Log False  [][])
    runTrans $
-    case (recover,rs) of
-      (True, Var x: rs') -> do setSData $ Log True rs' full
-                               return $ fromIDyn x              -- !!>  "read in Var:" ++ show x
+    case (recover ,rs) of        -- !> ("logged enter",recover,rs) of
+      (True, Var x: rs') -> do
+            setData $ Log True rs' full
+            return $ fromIDyn x
+--                                   !> ("read in Var:", x)
 
       (True, Exec:rs') -> do
-            setSData $ Log True  rs' full
-            mx                                 -- !!> "Var True Exec"
+            setData $ Log True  rs' full
+            mx                                  -- !> "Exec"
 
       (True, Wait:rs') -> do
-            setSData (Log True  rs' full)      -- !!> "Wait"
+            setData (Log True  rs' full)        -- !> "Wait"
             empty
 
       _ -> do
-            let add= Exec: full
-            setSData $ Log False add add
+--            let add= Exec: full
+            setData $ Log False (Exec : rs) (Exec: full)     -- !> ("setLog False", Exec:rs)
 
-            r <-  mx <*** ( do  -- when   p1 <|> p2, to avoid the re-execution of p1 at the
+            r <-  mx <** ( do  -- when   p1 <|> p2, to avoid the re-execution of p1 at the
                                 -- recovery when p1 is asynchronous
                             r <- getSData <|> return NoRemote
                             case r of
                                       WasParallel ->
-                                         let add= Wait: full
-                                         in setSData $ Log False add add
+--                                         let add= Wait: full
+                                           setData $ Log False (Wait: rs) (Wait: full)
                                       _ -> return ())
 
-
-            let add= Var (toIDyn r): full
-            (setSData $ Log False add add)     -- !!> "AFTER Var"
+            Log recoverAfter lognew _ <- getData `onNothing` return ( Log False  [][])
+            let add= Var (toIDyn r):  full
+            if recoverAfter && (not $ null lognew)      -- !> ("recoverAfter", recoverAfter)
+              then  (setData $ Log True lognew (reverse lognew ++ add) )
+                                                        -- !> ("recover",reverse lognew ,add)
+              else if recoverAfter && (null lognew) then
+                   setData $ Log False [] add
+              else
+                  (setData $ Log False (Var (toIDyn r):rs) add)  -- !> ("restore", (Var (toIDyn r):rs))
             return  r
 
-
-
-
-
-
-
---step :: (Show a, Read a, Typeable a) => TransientIO a -> TransientIO a
---step mx = step' mx $ \full mx -> do
---            let add= Exec: full
---            setSData $ Log False add add
---
---            r <-  mx
---
---            let add= Step (toIDyn r): full
---            (setSData $ Log False add add)     -- !!> "AFTER STEP"
---            return  r
---
---
 
 
src/Transient/Stream/Resource.hs view
@@ -74,52 +74,3 @@        v <- proc h  some
        liftIO $ myThreadId >>= print
        checkFinalize v
-
-type FinishReason= Maybe SomeException
-
-checkFinalize v=
-           case v of
-              SDone ->  finish Nothing >> stop
-              SLast x ->  finish Nothing >> return x
-              SError e -> liftIO ( print e) >> finish Nothing >> stop
-              SMore x -> return x
-
-
-
-data Finish= Finish (EVar FinishReason) deriving Typeable
-
--- | initialize the event variable for finalization.
--- all the following computations will share it
-initFinish :: TransIO Finish
-initFinish= do
-      fin <-  newEVar
-      let f = Finish fin
-      setSData  f
-      return  f
-
-
--- | suscribe a computation to be called when the finish event is triggered
-onFinish :: (FinishReason ->TransIO ()) -> TransIO ()
-onFinish  close= do
-       Finish finish <- getSData <|> initFinish
-
-       e <- readEVar finish
---       unsubscribe finish
-       close e  -- !!> "CLOSE"
-       stop
-     <|> return()
-
--- | trigger the event, so this closes all the resources
-finish :: FinishReason -> TransIO ()
-finish e= do
-    liftIO $ putStrLn "finish Called"
-    Finish finish <- getSData
-    writeEVar finish e
-
--- | deregister all the finalization actions.
--- A initFinish is needed to register actions again
-unFinish= do
-    Finish fin <- getSData
-    delEVar fin    -- !!> "DELEVAR"
-   <|> return ()   -- !!> "NOT DELEVAR"
-
transient.cabal view
@@ -1,6 +1,6 @@ name: transient
 
-version: 0.3
+version: 0.4.0
 cabal-version: >=1.10
 build-type: Simple
 license: MIT