packages feed

transient 0.1.0.4 → 0.1.0.8

raw patch · 11 files changed

+862/−789 lines, 11 filesdep +TCachedep +bytestringdep +timedep −transientdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: TCache, bytestring, time

Dependencies removed: transient

Dependency ranges changed: base

API changes (from Hackage documentation)

- Transient.Backtrack: instance Typeable Backtrack
- Transient.Base: EventValue :: SData -> EventValue
- Transient.Base: Loop :: Loop
- Transient.Base: Multithread :: Loop
- Transient.Base: Once :: Loop
- Transient.Base: children :: EventF -> TVar [EventF]
- Transient.Base: data EventValue
- Transient.Base: data Loop
- Transient.Base: fcomp :: EventF -> [b -> TransientIO b]
- Transient.Base: freeTh :: EventF -> Bool
- Transient.Base: instance Alternative TransientIO
- Transient.Base: instance Applicative TransientIO
- Transient.Base: instance Eq Loop
- Transient.Base: instance Eq RemoteStatus
- Transient.Base: instance Functor TransientIO
- Transient.Base: instance Monad TransientIO
- Transient.Base: instance MonadIO TransientIO
- Transient.Base: instance MonadPlus TransientIO
- Transient.Base: instance MonadState EventF TransientIO
- Transient.Base: instance Monoid a => Monoid (TransientIO a)
- Transient.Base: instance Read IDynamic
- Transient.Base: instance Read LogElem
- Transient.Base: instance Show IDynamic
- Transient.Base: instance Show LogElem
- Transient.Base: instance Typeable EventF
- Transient.Base: instance Typeable EventValue
- Transient.Base: instance Typeable Log
- Transient.Base: instance Typeable RemoteStatus
- Transient.Base: maxThread :: EventF -> Maybe (P Int)
- Transient.Base: mfData :: EventF -> Map TypeRep SData
- Transient.Base: mfSequence :: EventF -> Int
- Transient.Base: parent :: EventF -> Maybe EventF
- Transient.Base: runTrans :: TransIO x -> StateT EventF IO (Maybe x)
- Transient.Base: threadId :: EventF -> ThreadId
- Transient.Base: xcomp :: EventF -> TransientIO a
- Transient.EVars: instance Typeable EVars
- Transient.Move: connection :: Node -> Maybe (Handle, Socket, HostName, PortID)
- Transient.Move: host :: Node -> HostName
- Transient.Move: instance Eq Node
- Transient.Move: instance Ord PortID
- Transient.Move: instance Read Node
- Transient.Move: instance Read PortID
- Transient.Move: instance Read PortNumber
- Transient.Move: instance Show Node
- Transient.Move: instance Typeable Connection
- Transient.Move: instance Typeable Node
- Transient.Move: instance Typeable PortID
- Transient.Move: port :: Node -> PortID
+ Transient.Base: (!!>) :: c -> String -> c
+ Transient.Base: SDone :: StreamData a
+ Transient.Base: SError :: String -> StreamData a
+ Transient.Base: SLast :: a -> StreamData a
+ Transient.Base: SMore :: a -> StreamData a
+ Transient.Base: [children] :: EventF -> TVar [EventF]
+ Transient.Base: [event] :: EventF -> Maybe SData
+ Transient.Base: [fcomp] :: EventF -> [b -> TransientIO b]
+ Transient.Base: [freeTh] :: EventF -> Bool
+ Transient.Base: [maxThread] :: EventF -> Maybe (P Int)
+ Transient.Base: [mfData] :: EventF -> Map TypeRep SData
+ Transient.Base: [mfSequence] :: EventF -> Int
+ Transient.Base: [parent] :: EventF -> Maybe EventF
+ Transient.Base: [runTrans] :: TransIO x -> StateT EventF IO (Maybe x)
+ Transient.Base: [threadId] :: EventF -> ThreadId
+ Transient.Base: [xcomp] :: EventF -> TransientIO a
+ Transient.Base: addThreads :: (MonadIO m, MonadState EventF m) => Int -> m ()
+ Transient.Base: addThreads' :: Int -> TransIO ()
+ Transient.Base: data StreamData a
+ Transient.Base: getNonUsedThreads :: TransIO (Maybe Int)
+ Transient.Base: instance Control.Monad.IO.Class.MonadIO Transient.Base.TransientIO
+ Transient.Base: instance Control.Monad.State.Class.MonadState Transient.Base.EventF Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.Alternative Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.Applicative Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.Functor Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.Monad Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.MonadPlus Transient.Base.TransientIO
+ Transient.Base: instance GHC.Base.Monoid a => GHC.Base.Monoid (Transient.Base.TransientIO a)
+ Transient.Base: instance GHC.Classes.Eq Transient.Base.RemoteStatus
+ Transient.Base: instance GHC.Read.Read Transient.Base.IDynamic
+ Transient.Base: instance GHC.Read.Read Transient.Base.LogElem
+ Transient.Base: instance GHC.Read.Read a => GHC.Read.Read (Transient.Base.StreamData a)
+ Transient.Base: instance GHC.Show.Show Transient.Base.IDynamic
+ Transient.Base: instance GHC.Show.Show Transient.Base.LogElem
+ Transient.Base: instance GHC.Show.Show a => GHC.Show.Show (Transient.Base.StreamData a)
+ Transient.Base: keep' :: TransIO a -> IO a
+ Transient.Base: processLine :: String -> IO ()
+ Transient.Base: runContinuations :: [a -> TransIO b] -> c -> TransIO d
+ Transient.Base: waitEvents' :: IO b -> TransientIO b
+ Transient.DDS: cmap :: Loggable b => (a -> b) -> DDS a -> DDS b
+ Transient.DDS: distribute :: Loggable a => [a] -> DDS a
+ Transient.DDS: instance Data.TCache.Defs.Indexable (Transient.DDS.Partition a)
+ Transient.DDS: instance GHC.Read.Read (Transient.DDS.PartRef a)
+ Transient.DDS: instance GHC.Read.Read a => GHC.Read.Read (Transient.DDS.Partition a)
+ Transient.DDS: instance GHC.Show.Show (Transient.DDS.PartRef a)
+ Transient.DDS: instance GHC.Show.Show a => GHC.Show.Show (Transient.DDS.Partition a)
+ Transient.DDS: instance Transient.Logged.Loggable a => Data.TCache.IResource.IResource (Transient.DDS.Partition a)
+ Transient.DDS: instance Transient.Logged.Loggable a => GHC.Base.Monoid (Transient.DDS.DDS a)
+ Transient.DDS: reduce :: Loggable b => ([a] -> b) -> (b -> b -> b) -> b -> DDS a -> TransientIO b
+ Transient.Indeterminism: collect' :: Int -> NominalDiffTime -> NominalDiffTime -> TransientIO a -> TransientIO [a]
+ Transient.Indeterminism: groupByTime :: Integer -> TransientIO a -> TransientIO [a]
+ Transient.Logged: class (Show a, Read a, Typeable a) => Loggable a
+ Transient.Logged: instance (GHC.Show.Show a, GHC.Read.Read a, Data.Typeable.Internal.Typeable a) => Transient.Logged.Loggable a
+ Transient.Move: Pool :: [Handle] -> Int -> Pool
+ Transient.Move: [connection] :: Node -> IORef Pool
+ Transient.Move: [free] :: Pool -> [Handle]
+ Transient.Move: [host] :: Node -> HostName
+ Transient.Move: [pending] :: Pool -> Int
+ Transient.Move: [port] :: Node -> PortID
+ Transient.Move: assign :: MonadIO m => Int -> Node -> m Handle
+ Transient.Move: connectTo' :: Int -> HostName -> PortID -> IO Handle
+ Transient.Move: createNode :: HostName -> Integer -> Node
+ Transient.Move: data Pool
+ Transient.Move: emptyPool :: MonadIO m => m (IORef Pool)
+ Transient.Move: instance GHC.Classes.Eq Transient.Move.Node
+ Transient.Move: instance GHC.Classes.Ord Network.PortID
+ Transient.Move: instance GHC.Read.Read Network.PortID
+ Transient.Move: instance GHC.Read.Read Network.Socket.Types.PortNumber
+ Transient.Move: instance GHC.Read.Read Transient.Move.Node
+ Transient.Move: instance GHC.Show.Show Transient.Move.Node
+ Transient.Move: mclustered :: (Monoid a, Loggable a) => TransIO a -> TransIO a
+ Transient.Move: readHandler :: Read a => Handle -> IO (StreamData a)
+ Transient.Move: release :: MonadIO m => Node -> Handle -> m ()
+ Transient.Move: runAt :: Loggable a => Node -> TransIO a -> TransIO a
+ Transient.Move: setBufSize :: Int -> TransIO ()
+ Transient.Move: shuffleNodes :: MonadIO m => m [Node]
+ Transient.Move: streamFrom :: Loggable a => Node -> TransIO (StreamData a) -> TransIO (StreamData a)
+ Transient.Move: type Blocked = MVar ()
+ Transient.Move: type BuffSize = Int
+ Transient.Stream.Resource: finish :: TransIO ()
+ Transient.Stream.Resource: onFinish :: TransIO () -> TransIO a
+ Transient.Stream.Resource: process :: TransIO a -> IO handle -> (handle -> IO ()) -> (handle -> a -> TransIO (StreamData b)) -> TransIO b
+ Transient.Stream.Resource: sinkFile :: TransIO String -> String -> TransIO ()
+ Transient.Stream.Resource: sourceFile :: String -> TransIO String
- Transient.Base: (!>) :: b -> b1 -> b
+ Transient.Base: (!>) :: a -> b -> a
- Transient.Base: EventF :: TransientIO a -> [b -> TransientIO b] -> Map TypeRep SData -> Int -> ThreadId -> Bool -> Maybe EventF -> TVar [EventF] -> Maybe (P Int) -> EventF
+ Transient.Base: EventF :: Maybe SData -> TransientIO a -> [b -> TransientIO b] -> Map TypeRep SData -> Int -> ThreadId -> Bool -> Maybe EventF -> TVar [EventF] -> Maybe (P Int) -> EventF
- Transient.Base: delSessionData :: (MonadState EventF m, Typeable * a) => a -> m ()
+ Transient.Base: delSessionData :: (Typeable * a, MonadState EventF m) => a -> m ()
- Transient.Base: getCont :: MonadState EventF m => m EventF
+ Transient.Base: getCont :: (MonadState EventF m) => m EventF
- Transient.Base: getLine' :: (Typeable * a, Read a) => (a -> Bool) -> IO a
+ Transient.Base: getLine' :: (Read a, Typeable * a) => (a -> Bool) -> IO a
- Transient.Base: inputLoop :: IO ()
+ Transient.Base: inputLoop :: IO b
- Transient.Base: keep :: TransientIO x -> IO b
+ Transient.Base: keep :: TransIO a -> IO a
- Transient.Base: loop :: EventF -> IO (Either a a1) -> IO ()
+ Transient.Base: loop :: EventF -> IO (StreamData t) -> IO ()
- Transient.Base: parallel :: IO (Either b b) -> TransientIO b
+ Transient.Base: parallel :: IO (StreamData b) -> TransientIO (StreamData b)
- Transient.Base: reads1 :: (Typeable * a, Read a) => String -> [(a, String)]
+ Transient.Base: reads1 :: (Read a, Typeable * a) => String -> [(a, String)]
- Transient.Base: waitQSemB :: (Ord a, Num a) => IORef a -> IO Bool
+ Transient.Base: waitQSemB :: (Num a, Ord a) => IORef a -> IO Bool
- Transient.Logged: toIDyn :: (Typeable * a, Show a, Read a) => a -> IDynamic
+ Transient.Logged: toIDyn :: (Read a, Show a, Typeable * a) => a -> IDynamic
- Transient.Move: Connection :: PortID -> Handle -> Socket -> Connection
+ Transient.Move: Connection :: (Maybe (PortID, Handle, Socket, Blocked)) -> BuffSize -> Connection
- Transient.Move: Node :: HostName -> PortID -> Maybe (Handle, Socket, HostName, PortID) -> Node
+ Transient.Move: Node :: HostName -> PortID -> IORef Pool -> Node
- Transient.Move: addNodes :: [Node] -> TransIO ()
+ Transient.Move: addNodes :: MonadIO m => [Node] -> m ()
- Transient.Move: beamInit :: PortID -> TransIO a -> IO b
+ Transient.Move: beamInit :: Node -> TransIO a -> IO a
- Transient.Move: beamTo :: HostName -> PortID -> TransientIO ()
+ Transient.Move: beamTo :: Node -> TransientIO ()
- Transient.Move: callTo :: (Show a, Read a, Typeable a) => HostName -> PortID -> TransIO a -> TransIO a
+ Transient.Move: callTo :: Loggable a => Node -> TransIO a -> TransIO a
- Transient.Move: callTo' :: (Show a, Read a, Typeable a) => HostName -> PortID -> TransIO a -> TransIO a
+ Transient.Move: callTo' :: (Show a, Read a, Typeable a) => Node -> TransIO a -> TransIO a
- Transient.Move: clustered :: (Typeable a, Show a, Read a) => Monoid a => TransIO a -> TransIO a
+ Transient.Move: clustered :: Loggable a => TransIO a -> TransIO a
- Transient.Move: clustered' :: (Typeable * b, Show b, Read b) => TransIO b -> TransientIO [b]
+ Transient.Move: clustered' :: (Read b, Show b, Typeable * b) => TransIO b -> TransientIO [b]
- Transient.Move: connect :: HostName -> PortID -> HostName -> PortID -> TransientIO ()
+ Transient.Move: connect :: Node -> Node -> TransientIO ()
- Transient.Move: forkTo :: HostName -> PortID -> TransientIO ()
+ Transient.Move: forkTo :: Node -> TransientIO ()
- Transient.Move: getNodes :: TransIO [Node]
+ Transient.Move: getNodes :: MonadIO m => m [Node]
- Transient.Move: installService :: HostName -> PortID -> t -> [Char] -> TransIO ()
+ Transient.Move: installService :: Node -> t -> [Char] -> TransIO ()
- Transient.Move: listen :: PortID -> TransIO ()
+ Transient.Move: listen :: Node -> TransIO ()
- Transient.Move: setMyNode :: MonadIO m => t -> t1 -> m ()
+ Transient.Move: setMyNode :: MonadIO m => a -> m ()

Files

− Main.hs
@@ -1,386 +0,0 @@-
-
-{-# LANGUAGE ScopedTypeVariables #-}
-
-{-# LANGUAGE DeriveDataTypeable  #-}
-module Main where
-
-import           Data.Typeable
-import           Transient.Base
-import           Transient.Backtrack
-import           Transient.Indeterminism
-import           Transient.Logged
-import           Transient.Move
-import           Transient.EVars
-import           Control.Applicative
-import           Control.Concurrent
-import           Control.Exception
-import           Control.Monad.State
-import           Data.Monoid
-import           System.IO.Unsafe
-import           System.Directory
-import           System.FilePath
-import           Network.HTTP
-import           Network
-import           System.IO
-import           Data.IORef
-
-import Data.List hiding (find,map, group)
-
-
-main= keep $ do
-      oneThread $ option "main" "to kill previous spawned processes and return to the main menu"   <|> return ""
-      liftIO $ putStrLn "MAIN MENU"
-
-      nonDeterminsm <|> trans <|>
-             colors <|> app   <|>
-            futures <|> server <|>
-            distributed <|> pubSub
-
-solveConstraint=  do
-      x <- choose  [1,2,3]
-      y <- choose  [4,5,6]
-
-      guard $ x * y == 8
-
-      return (x,y)
-
-pythags = freeThreads $ do
-  x <- choose [1..50]
-  y <- choose ([1..x] :: [Int])
-  z <- choose [1..round $ sqrt(fromIntegral $ 2*x*x)]
-
-  guard (x*x+y*y==z*z)
-  th <- liftIO $  myThreadId
-  return (x, y, z, th)
-
-example1= do
-    option "ex1" "example 1"
-    r <- threads 4 solveConstraint
-    liftIO $ print r
-
-example2= do
-    option "pyt" "pythagoras"
-    r<- threads 2 pythags
-    liftIO $ print r
-
-collectSample= threads 4 $ do
-    option "coll" "group sample: return results in a list"
-    r <- collect 0 $ do
-      x <- choose  [1,2,3]
-      y <- choose  [4,5,6]
-      th <- liftIO $ threadDelay 1000 >> myThreadId
-
-      return (x,y,th)
-
-    liftIO $ print r
-
-threadSample= do
-     option "th" "threads sample"
-     liftIO $ print "number of threads? (< 10)"
-
-     n <- input  ( < 10)
-
-     threads n $ do
-        x <- choose  [1,2,3]
-        y <- choose  [4,5,6]
-        th <- liftIO $ myThreadId
-        liftIO $ print (x,y,th)
-
-nonDeterminsm= do
-      option "nondet" "Non determinism examples"
-      example1 <|> example2
-               <|> collectSample
-               <|> threadSample
-               <|> fileSearch
-
-
-
-find' :: String -> FilePath -> TransientIO FilePath
-find' s d = do
-  fs <- liftIO $ getDirectoryContents d
-       `catch` \(e:: SomeException) -> return []       -- 1
-  let fs' = sort $ filter (`notElem` [".",".."]) fs    -- 2
-  if any (== s) fs'                                    -- 3
-     then do
-       liftIO $ print $ d </> s
-       return $ d</> s
-     else do
-       f <- choose fs'                                 -- 4
-       let d' = d </> f                                -- 6
-       isdir <- liftIO $ doesDirectoryExist d'         -- 7
-       if isdir then find' s d'                        -- 8
-                else stop
-
-
-------------------
-
-fileSearch=   do
-    option "file" "example of file search"
-    r<- threads 3 $ collect 10 $ find' "Main.hs"  "."
-    liftIO $ putStrLn $ "SOLUTION= "++ show  r
---    exit
-
-
-
-
-
-
-
-trans= do
-       option "trans" "transaction examples with backtracking for undoing actions"
-       transaction <|> transaction2
-
-transaction=   do
-       option "back" "backtracking test"
-       productNavigation
-       reserve
-       payment
-
-transaction2= do
-       option "back2" "backtracking test 2"
-       productNavigation
-       reserveAndSendMsg
-       payment
-
-
-       liftIO $ print "done!"
-
-
-productNavigation = liftIO $ putStrLn "product navigation"
-
-reserve= liftIO (putStrLn "product reserved,added to cart")
-                 `onUndo` liftIO (putStrLn "product un-reserved")
-
-payment = do
-           liftIO $ putStrLn "Payment failed"
-           undo
-
-reserveAndSendMsg= do
-            reserve
-            liftIO  (putStrLn "update other database necesary for the reservation")
-                 `onUndo` liftIO (putStrLn "database update undone")
-
-
-
-colors :: TransientIO ()
-colors= do
-       option "colors" "choose between three colors"
-       r <-  color 1  "red"  <|> color 2 "green" <|> color 3 "blue"
-       liftIO $ print r
-       where
-       color :: Int -> String -> TransientIO String
-       color n str= do
-         option (show n) str
-         liftIO . print $ str ++ " color"
-         return  str
-
-app :: TransientIO ()
-app= do
-       option "app" "applicative expression that return a counter in 2-tuples every second"
-       liftIO $ putStrLn "to stop the sequence, write main(enter)"
-       counter <- liftIO $ newMVar 0
-
-       r <-  (,) <$>  number  counter 1 <*> number counter 1
-
-
-       liftIO $ putStrLn $ "result=" ++ show r
-       where
-       number counter n= waitEvents $ do
-          threadDelay $ n * 1000000
-          n <- takeMVar counter
-          putMVar counter (n+1)
-          return n
-
-futures= do
-       option "async" "for parallelization of IO actions with applicative and monoidal combinators"
-       sum1 <|> sum2
-
-sum1 :: TransientIO ()
-sum1= do
-       option "sum1" "access to two web pages concurrently and sum the number of words using Applicative"
-       liftIO $ print " downloading data..."
-       (r,r') <- (,) <$> async  (worker "http://www.haskell.org/")
-                     <*> async  (worker "http://www.google.com/")
-
-       liftIO $ putStrLn $ "result="  ++ show  (r + r')
-
-getURL= simpleHTTP . getRequest
-
-worker :: String -> IO Int
-worker url=do
-      r <- getURL url
-      body <- getResponseBody r
-      putStrLn $ "number of words in " ++ url ++" is: " ++ show(length (words body))
-      return . length . words $ body
-
-sum2 :: TransientIO ()
-sum2= do
-      option "sum2" "access to N web pages concurrenty and sum the number of words using map-fold"
-      liftIO $ print " downloading data..."
-      rs <- foldl (<>) (return 0) $ map (async . worker)
-                  [ "http://www.haskell.org/"
-                  , "http://www.google.com/"]
-
-      liftIO $ putStrLn $ "result="  ++ show rs
-
-instance Monoid Int where
-      mappend= (+)
-      mempty= 0
-
-server :: TransientIO ()
-server=  do
-       option "server" "A web server in the port 8080"
-       liftIO $ print "Server Stated"
-       sock <-  liftIO $  listenOn $ PortNumber 8080
-
-       (h,_,_) <- spawn $ accept sock `catch` (\(e::SomeException) -> sClose sock >> throw e)
-       liftIO $ do
-           hPutStr h msg
-           putStrLn "new request"
-           hFlush h
-           hClose h
-         `catch` (\(e::SomeException) -> sClose sock)
-
-msg = "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nPong!\r\n"
-
-
--- distributed computing
-
-distributed= do
-      option "distr" "examples of distributed computing"
-      let port1 = PortNumber 2000
-
-
-      addNodes [Node host port1 Nothing]
-      listen port1 <|> return ()-- conn port1 port1 <|> conn port2 port1
-
-      examples' host port1
-      where
-      host= "localhost"
-      conn p p'=  connect host p host p'
-
-examples' remoteHost remotePort= do
-   logged $ option "maind"  "to see this menu" <|> return ""
-   r <-logged    $ option "move" "move to another node"
-               <|> option "call" "call a function in another node"
-               <|> option "chat" "chat"
-               <|> option "netev" "events propagating trough the network"
-   case r of
-       "call"  -> callExample remoteHost remotePort
-       "move"  -> moveExample remoteHost remotePort
-       "chat"  -> chat
-       "netev" -> networkEvents remoteHost remotePort
-
-
-callExample host port= do
-   logged $ putStrLnhp  port "asking for the remote data"
-   s <- callTo host port $ liftIO $ do
-                       putStrLnhp  port "remote callTo request"
-                       readIORef environ
-
-
-   liftIO $ putStrLn $ "resp=" ++ show s
-
-
-environ= unsafePerformIO $ newIORef "Not Changed"
-
-moveExample host port= do
-   putStrLnhp  port "enter a string. It will be inserted in the other node by a migrating program"
-   name <- logged $ input (const True)
-   beamTo host port
-   putStrLnhp  port "moved!"
-   putStrLnhp  port $ "inserting "++ name ++" as new data in this node"
-   liftIO $ writeIORef environ name
-   return()
-
-
-chat ::  TransIO ()
-chat  = do
-    name  <- logged $ do liftIO $ putStrLn "Name?" ; input (const True)
-    text <- logged $  waitEvents  $ putStr ">" >> hFlush stdout >> getLine' (const True)
-    let line= name ++": "++ text
-    clustered $   liftIO $ putStrLn line
-
-
-networkEvents rh rp= do
-     logged $  do
-       putStrLnhp  rp "callTo is not  a simole remote call. it stablish a connection"
-       putStrLnhp  rp "between transient processes in different nodes"
-       putStrLnhp  rp "in this example, events are piped back from a remote node to the local node"
-
-     r <- callTo rh rp $ do
-                         option "fire"  "fire event"
-                         return "event fired"
-     putStrLnhp  rp $ r ++ " in remote node"
-
-putStrLnhp p msg= liftIO $ putStr (show p) >> putStr " ->" >> putStrLn msg
-
-
-pubSub=  do
-  option "pubs" "an example of publish-subscribe using Event Vars (EVars)"
-  v  <- newEVar  :: TransIO (EVar String)
-
-  v' <- newEVar 
-  subscribe v v' <|> publish v v'
-  where
-      
-  publish v v'= do
-    liftIO $ putStrLn "Enter a message to publish"
-    msg <-  input(const True)
-
-    writeEVar v msg
-    liftIO $ putStrLn "after writing first EVar\n"
-    writeEVar v' $ "second " ++ msg
-    liftIO $ putStrLn "after writing second EVar\n"
-    publish v v'
-
-
-  subscribe :: EVar String -> EVar String -> TransIO ()
-  subscribe v v'= do
-       r <- (,) <$> proc1 v  <*>  proc2 v'
-       liftIO $ do
-             putStr "applicative result= "
-             print r
-
-  susbcribe2 ::  EVar String -> EVar String -> TransIO ()
-  susbcribe2 v v'= do
-        x <- readEVar v
-        y <- readEVar v'
-        liftIO $ do
-                 putStr "monadic result"
-                 print (x,y)
-
-  proc1 v=  do
-    msg <- readEVar v
-    liftIO $ putStrLn $  "proc1 readed var: " ++ show msg
-    return msg
-
-  proc2 v= do
-    msg <- readEVar v
-    liftIO $ putStrLn $ "proc2 readed var: " ++ show msg
-    return msg
-
-
-
-
-
-
---main=do
---      r <- getURL "https://www.w3.org/services/html2txt?url=http%3A%2F%2Fwww.searchquotes.com%2Fsearch%2Ftransient%2F"
---      body <- getResponseBody r
---      print $ parse  quote' "" body
---      where
---      quote'= do
---          q <-  between(brackets natural) (brackets natural) string
---
---          if "http" `isPrefixOf` q
---            then quote'
---            else  return q
---
-
---main    = case (parse numbers "" "11, 2, 43") of
---            Left err  -> print err
---            Right xs  -> print (sum xs)
---
---numbers = commaSep integer
− move.hs
@@ -1,178 +0,0 @@-{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}
-module Main where
-
-import Transient.Move
-import Transient.Logged
-import Transient.Base
-import Network
-import Control.Applicative
-
-import Control.Monad.IO.Class
-import System.Environment
-import System.IO.Unsafe
-import Data.Monoid
-import System.IO
-import Control.Monad
-import Data.Maybe
-import Control.Exception
-import Control.Concurrent (threadDelay)
-import Data.Typeable
-import Control.Concurrent.STM
-import Data.IORef
--- some tests for distributed computing
-
---main= do
---      let port1 = PortNumber 2000
---          port2 = PortNumber 2001
---
---
---      keep $  do
---        conn port1 port1 <|> conn port2 port1
---
---        examples' host port2
---      where
---      host= "localhost"
-----      delay = liftIO $ threadDelay 1000000
---      conn p p'=  connect host p host p'
---
---
---
---
---
---test = do
---   args <- getArgs
---   let ports= [("localhost",PortNumber 2000), ("localhost",PortNumber 2001)]
---
---   let [(_,port1), (_,port2)]= if null args  then ports else reverse ports
---   print [port1, port2]
---   let local= "localhost"
---   beamInit port1 $ do
---           logged $ option "call" "call"
---           callTo local port2 (liftIO $ print "HOLA")
---             <|> callTo local port2(liftIO $ print "HELLO")
-
-
--- to be executed with two or more nodes
-main = do
-  args <- getArgs
-  if length args < 2
-    then do
-     putStrLn "The program need at least two parameters:  localHost localPort  remoteHost RemotePort"
-     putStrLn "Start one node alone. The rest, connected to this node."
-     return ()
-    else keep $ do
-       let localHost= head args
-           localPort= PortNumber . fromInteger . read $ args !! 1
-           (remoteHost,remotePort) =
-             if length args >=4
-                then(args !! 2, PortNumber . fromInteger . read $ args !! 3)
-                else (localHost,localPort)
-       connect localHost localPort remoteHost remotePort
-       examples
-
-
-examples =  do
-   logged $ option "main"  "to see the menu" <|> return ""
-   r <-logged      $ option "move" "move to another node"
-               <|> option "call" "call a function in another node"
-               <|> option "chat" "chat"
-               <|> option "netev" "events propagating trough the network"
-   case r of
-       "call" -> callExample
-       "move" -> moveExample
-       "chat" -> chat
-       "netev" -> networkEvents
-
-data Environ= Environ (IORef String) deriving Typeable
-
-callExample = do
-   nodes <- logged getNodes
-   let Node host port _=  head $ tail nodes
-
-   logged $ putStrLnhp  port "asking for the remote data"
-   s <- callTo host port $  do
-                       putStrLnhp  port "remote callTo request"
-                       liftIO $ readIORef environ
-
-
-   liftIO $ putStrLn $ "resp=" ++ show s
-
-
-environ= unsafePerformIO $ newIORef "Not Changed"
-
-moveExample = do
-   nodes <- logged getNodes
-   let Node host port _=  head $ tail nodes
-
-   putStrLnhp  port "enter a string. It will be inserted in the other node by a migrating program"
-   name <- logged $ input (const True)
-   beamTo host port
-   putStrLnhp  port "moved!"
-   putStrLnhp  port $ "inserting "++ name ++" as new data in this node"
-
-
-   liftIO $ writeIORef environ name
-   return()
-
-
-chat ::  TransIO ()
-chat  = do
-    name  <- logged $ do liftIO $ putStrLn "Name?" ; input (const True)
-    text <- logged $  waitEvents  $ putStr ">" >> hFlush stdout >> getLine' (const True)
-    let line= name ++": "++ text
-    clustered $   liftIO $ putStrLn line
-
-
-networkEvents = do
-     nodes <- logged getNodes
-     let Node rh rp _=  head $ tail nodes
-     logged $  do
-       putStrLnhp  rp "callTo is not  a simole remote call. it stablish a connection"
-       putStrLnhp  rp "between transient processes in different nodes"
-       putStrLnhp  rp "in this example, events are piped back from a remote node to the local node"
-
-     r <- callTo rh rp $ do
-                         option "fire"  "fire event"
-                         return "event fired"
-     putStrLnhp  rp $ r ++ " in remote node"
-
-putStrLnhp p msg= liftIO $ putStr (show p) >> putStr " ->" >> putStrLn msg
-
-
-
-
-
---call host port proc params= do
---   port <- getPort
---   listen port <|> return
---   parms <- logged $ return params
---   callTo host port proc parms
---   close
---
---distribute proc= do
---   case dataFor proc
---    Nothing -> proc
---    Just dataproc -> do
---      (h,p) <- bestNode dataproc
---      callTo h p proc
---
---bestNode dataproc=
---   nodes <- getNodes
---      (h,p) <- bestMatch dataproc nodes   <- user defined
---
---bestMatch (DataProc nodesAccesed cpuLoad resourcesNeeded)  nodes= do
---   nodesAccesed: node, response
---
---bestMove= do
---   thisproc <- gets myProc
---   case dataFor thisproc
---      Nothing -> return ()
---      Just dataproc -> do
---        (h,p) <- bestNode dataproc
---        moveTo h p
---
---
---inNetwork= do
---   p <- getPort
---   listen p <|> return ()
-
src/Transient/Backtrack.hs view
@@ -25,20 +25,19 @@ -- | the secod parameter will be executed when backtracking
 {-# NOINLINE onUndo #-}
 onUndo :: TransientIO a -> TransientIO a -> TransientIO a
-onUndo ac bac= do
-   r<-registerUndo $ Transient $ do
+onUndo ac bac= registerUndo $ Transient $ do
      Backtrack back _ <- getSessionData `onNothing` return (Backtrack False [])
      runTrans $ if back then bac  else ac
-   return r
 
+
 -- | register an action that will be executed when backtracking
 {-# NOINLINE registerUndo #-}
 registerUndo :: TransientIO a -> TransientIO a
 registerUndo f  = Transient $ do
-   cont@(EventF x _ _ _ _ _ _ _ _)  <- get   !> "backregister"
+   cont@(EventF _ x _ _ _ _ _ _ _ _)  <- get   !> "backregister"
    md  <- getSessionData
    ss <- case md of
-        Just (bss@(Backtrack b (bs@((EventF x'  _ _ _ _ _ _ _ _):_)))) -> do
+        Just (bss@(Backtrack b (bs@((EventF _ x'  _ _ _ _ _ _ _ _):_)))) -> do
             addrx  <- addr x
             addrx' <- addr x'         -- to avoid duplicate backtracking points
             return $ if addrx == addrx' then bss else  Backtrack b $ cont:bs
@@ -67,7 +66,7 @@   where
   nullBack= Backtrack False []
   goBackt (Backtrack _ [])= return Nothing                     !> "END"
-  goBackt (Backtrack b (stack@(first@(EventF x fs _ _  _ _ _ _ _): bs)))= do
+  goBackt (Backtrack b (stack@(first@(EventF _ x fs _ _  _ _ _ _ _): bs)))= do
 --        put first{replay=True}
         setSData $ Backtrack True stack
         mr <-  runClosure first                                !> "RUNCLOSURE"
src/Transient/Base.hs view
@@ -37,11 +37,14 @@ import           GHC.Conc
 import           Data.List
 import           Data.IORef
+import           System.Environment
 
 
 {-# INLINE (!>) #-}
 (!>) =  const . id -- flip trace
 infixr 0 !>
+(!!>) =   flip trace
+infixr 0 !!>
 
 data TransIO  x = Transient  {runTrans :: StateT EventF IO (Maybe x)}
 type SData= ()
@@ -50,7 +53,8 @@ 
 type TransientIO= TransIO
 
-data EventF  = forall a b . EventF{xcomp       :: TransientIO a
+data EventF  = forall a b . EventF{event       :: Maybe SData
+                                  ,xcomp       :: TransientIO a
                                   ,fcomp       :: [b -> TransientIO b]
                                   ,mfData      :: M.Map TypeRep SData
                                   ,mfSequence  :: Int
@@ -93,7 +97,7 @@ runTransient t= do
 
   th <- myThreadId
-  let eventf0=  EventF  empty [] M.empty 0
+  let eventf0=  EventF  Nothing empty [] M.empty 0
           th False  Nothing  (unsafePerformIO $ newTVarIO []) Nothing
 
 
@@ -108,7 +112,7 @@ 
 -- | run the continuation context
 runCont :: EventF -> StateIO ()
-runCont (EventF  x fs _ _  _ _  _ _ _)= runTrans ((unsafeCoerce x') >>= compose ( fs)) >> return ()
+runCont (EventF _ x fs _ _  _ _  _ _ _)= runTrans ((unsafeCoerce x') >>= compose ( fs)) >> return ()
     where
     x'=  do
 --           modify $ \s -> s{replay=True}
@@ -131,12 +135,19 @@ 
 -- | run the closure  (the 'x'  in 'x >>= f') of the current bind operation.
 runClosure :: EventF -> StateIO (Maybe a)
-runClosure (EventF x _ _ _ _ _ _ _ _) =  unsafeCoerce $ runTrans x
+runClosure (EventF _ x _ _ _ _ _ _ _ _) =  unsafeCoerce $ runTrans x
 
 -- | run the continuation (the 'f' in 'x >> f') of the current bind operation
 runContinuation ::  EventF -> a -> StateIO (Maybe b)
-runContinuation (EventF _ fs _ _ _ _  _ _ _) x= runTrans $  (unsafeCoerce $ compose $  fs) x
+runContinuation (EventF _ _ fs _ _ _ _  _ _ _) x=
+   runTrans $  (unsafeCoerce $ compose $  fs)  x
 
+-- | run a chain of continuations. It is up to the programmer to assure by construction that
+--  each continuation type-check with the next and the parameter type match the input of the first
+-- continuation and that the output is of the type intended.
+runContinuations :: [a -> TransIO b] -> c -> TransIO d
+runContinuations fs x= (compose $ unsafeCoerce fs)  x
+
 instance   Functor TransientIO where
   fmap f mx=   -- Transient $ fmap (fmap f) $ runTrans mx
     do
@@ -152,7 +163,7 @@          rf <- liftIO $ newIORef Nothing
          rg <- liftIO $ newIORef Nothing   -- !> "NEWIOREF"
 
-         cont@(EventF _ fs a b c d peers children g1) <- get   -- !> "APLICATIVE DOIT"
+         cont@(EventF _ _ fs a b c d peers children g1) <- get   -- !> "APLICATIVE DOIT"
 
          let
              appg x = Transient $  do
@@ -168,7 +179,7 @@ 
 
 
-         put $ EventF f (unsafeCoerce appf:  fs)
+         put $ EventF Nothing f (unsafeCoerce appf:  fs)
                                           a b c d peers children g1
          k <- runTrans f
          was <- getSessionData `onNothing` return NoRemote
@@ -178,7 +189,7 @@              liftIO $ writeIORef rf  k -- :: StateIO ()
 
              mfdata <- gets mfData
-             put $ EventF g (unsafeCoerce appg :  fs) mfdata b c d peers  children g1
+             put $ EventF Nothing g (unsafeCoerce appg :  fs) mfdata b c d peers  children g1
 
 
              x <- runTrans g              !> "RUN g"
@@ -237,20 +248,20 @@ -- | set the current closure and continuation for the current statement
 setEventCont ::   TransientIO a -> (a -> TransientIO b) -> StateIO ()
 setEventCont x f  = do
-   st@(EventF   _ fs d n  r applic  ch rc bs)  <- get
-   put $ EventF x ( unsafeCoerce f : fs) d n  r applic  ch rc bs
+   st@(EventF  e _ fs d n  r applic  ch rc bs)  <- get
+   put $ EventF e x ( unsafeCoerce f : fs) d n  r applic  ch rc bs
 
 
 -- | reset the closure and continuation. remove inner binds than the prevous computations may have stacked
 -- in the list of continuations.
 resetEventCont :: Maybe a -> StateIO ()
 resetEventCont mx =do
-   st@(EventF _ fs d n  r nr  ch rc bs)  <- get
+   st@(EventF e _ fs d n  r nr  ch rc bs)  <- get
 
    let f= \mx ->  case mx of
                        Nothing -> empty
                        Just x  -> (unsafeCoerce $ head fs)  x
-   put $ EventF  (f mx) ( tailsafe fs)d n  r nr  ch rc bs
+   put $ EventF e (f mx) ( tailsafe fs)d n  r nr  ch rc bs
    where
    tailsafe []=[]
    tailsafe (x:xs)= xs
@@ -286,7 +297,8 @@ waitQSemB sem= atomicModifyIORef sem $ \n -> if n > 0 then(n-1,True) else (n,False)
 signalQSemB sem= atomicModifyIORef sem  $ \n ->  (n + 1,())
 
--- | set the maximun number of threads for a procedure. It is useful for the
+-- | set the maximun number of threads for a procedure. It is useful to limit the
+-- parallelization of transient code that uses `parallel` `spawn` and `waitEvents`
 threads :: Int -> TransientIO a -> TransientIO a
 threads n proc= Transient $ do
    msem <- gets maxThread
@@ -305,8 +317,31 @@    killChilds
    return r
 
+-- | add n threads to the limit of threads. If there is no limit, it set it
+addThreads' :: Int -> TransIO ()
+addThreads' n= do
+   msem <- gets maxThread
+   case msem of
+    Just sem -> liftIO $ modifyIORef sem $ \n' -> n + n'
+    Nothing  -> do
+        sem <- liftIO (newIORef n)
+        modify $ \ s -> s{maxThread= Just sem}
 
+-- | assure that at least there are n threads left
+addThreads n= do
+   msem <- gets maxThread
+   case msem of
+     Nothing -> return ()
+     Just sem ->  liftIO $ modifyIORef sem $ \n' -> if n' > n then n' else  n
 
+getNonUsedThreads :: TransIO (Maybe Int)
+getNonUsedThreads= do
+   msem <- gets maxThread
+   case msem of
+    Just sem -> liftIO $ Just <$> readIORef sem
+    Nothing -> return Nothing
+
+
 -- | The threads generated in the process passed as parameter will not be killed.
 freeThreads :: TransientIO a -> TransientIO a
 freeThreads proc= Transient $ do
@@ -316,7 +351,7 @@      modify $ \st -> st{freeTh= freeTh st}
      return r
 
--- | The threads will be killed when the parent thread dies. That is the default
+-- | The threads will be killed when the parent thread dies. That is the default.
 -- This can be invoked to revert the effect of `freeThreads`
 hookedThreads :: TransientIO a -> TransientIO a
 hookedThreads proc= Transient $ do
@@ -400,93 +435,114 @@ refSequence= unsafePerformIO $ newp 0
 
 
+-- | async calls
 
-data Loop= Once | Loop | Multithread deriving Eq
+data StreamData a=  SMore a | SLast a | SDone | SError String deriving (Typeable, Show,Read)
 
+
 -- | variant of `parallel` that repeatedly executes the IO computation and kill the previously created childs
+--
+-- It is useful in single threaded problems where each event discard the computations spawned by
+-- previous events
 waitEvents ::   IO b -> TransientIO b
 waitEvents io= do
-   r <- parallel (Right <$> io)
+   SMore r <- parallel (SMore <$> io)
    killChilds
    return r
 
+-- Multithreaded version of `waitEvents` that do not kill the computations spawned by previous events
+waitEvents' ::   IO b -> TransientIO b
+waitEvents' io= do
+   SMore r <- parallel (SMore <$> io)
+   return r
+
 -- | variant of + parallel` that execute the IO computation once, and kill the previous child threads
 async  ::  IO b -> TransientIO b
 async io= do
-   r <- parallel  (Left <$>io)
+   SLast r <- parallel  (SLast <$>io)
    killChilds
    return r
 
+-- | variant that spawn free threads. Since there is not thread control, this is faster
 spawn ::  IO b -> TransientIO b
 spawn io= freeThreads $ do
-   r <- parallel (Right <$>io)
+
+   SMore r <- parallel (SMore <$>io)
    return r
 
-data EventValue= EventValue SData deriving Typeable
 
+
+
+
 -- |  return empty to the current thread and launch the IO action in a new thread and attaches the continuation after it.
 -- if the result of the action is `Right` the process is repeated. if not, it finish.
 --
 -- If the maximum number of threads, set with `threads` has been reached  `parallel` perform
 -- the work sequentially, in the current thread.
 --
--- when finish, increase the counter of threads available, if there is a limitation of them.
-
-parallel  ::    IO (Either b b) -> TransientIO b
-parallel  ioaction= Transient$   do
+-- When `parallel`finish, increase the counter of threads available, if there is a limitation of them.
+--
+-- The behaviour of `parallel` depend on `StreamData` if `SMore`, `parallel` will excute again the
+-- IO action. with `SLast`, `SDone` and `SError`, `parallel` will execute the continuation and will stop.
+parallel  ::    IO (StreamData b) -> TransientIO (StreamData b)
+parallel  ioaction= Transient $   do
     cont <- getCont                    -- !> "PARALLEL"
-    mv <- getSessionData
-    case mv  of
-     Just (EventValue v)  -> do
-        delSessionData $ EventValue () -- !> "ISJUST "
-        return  $ Just $ unsafeCoerce v
+    case event cont of
+     j@(Just _) -> do
+        put cont{event=Nothing}
+        return $ unsafeCoerce j
      Nothing -> do
-        liftIO  $ loop cont    ioaction
+        liftIO $ loop cont ioaction
         return Nothing
 
-
-
-
-loop (cont'@(EventF x fs a b c d peers childs g))  rec  =  do
+-- executes the an IO action and then the continuation included in the first parameter
+loop :: EventF -> IO (StreamData t) -> IO ()
+loop (cont'@(EventF e x fs a b c d peers childs g))  rec  =  do
   chs <- liftIO $ newTVarIO []
-  let cont = EventF x fs a b c d (Just cont') chs g
-      iocont dat=
-          runStateT ( do
-             setSessionData . EventValue $ unsafeCoerce dat
-             runCont cont
-             ) cont
-             >> return ()
-      loop'= do
-        mdat <- rec
-        case mdat of
-         Left dat -> iocont dat
+  let cont = EventF e x fs a b c d (Just cont') chs g
+      iocont dat= do
+          runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat}
+          return ()
 
-         Right dat -> do
-              forkMaybe cont $ iocont dat
-              loop'
+      -- execute the IO computation and then the closure-continuation
+      loop'= forkMaybe False cont $ do
+         mdat <- rec
+         case mdat of
+             se@(SError _) -> iocont se
+             SDone -> iocont SDone
+             last@(SLast _) -> iocont last
 
-  forkMaybe  cont loop'
+             more@(SMore _) -> do
+                  forkMaybe False cont $ iocont more
+                  loop'
+
+  loop'
+  return ()
   where
-      forkMaybe cont proc = do
-         dofork <- case maxThread cont of
+  forkMaybe True cont proc = forkMaybe' True cont proc
+  forkMaybe False cont proc = do
+     dofork <- case maxThread cont of
                   Nothing -> return True
                   Just sem -> do
                     dofork <- waitQSemB sem
                     if dofork then  return True else return False
+     forkMaybe' dofork cont proc
 
+  forkMaybe' dofork cont proc=
          if dofork
             then  do
                  th <- forkFinally1 proc $ \me -> do
-                         case me of -- !> "THREAD ENDED" of
+                         case me of -- !> "THREAD END" of
                           Left  e -> do
-                           when (fromException e /= Just ThreadKilled)$ liftIO $ print e
-                           killChildren  cont  !> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
 
-                          Right _ -> do
+                             when (fromException e /= Just ThreadKilled)$ liftIO $ print e
+                             killChildren  cont  !> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
+
+                          Right _ -> when(not $ freeTh cont') $ do -- if was not a free thread
                              --  if parent is alive
                              --  then remove himself from the list (with free)
                              --  and pass his active children to his parent
-                             return ()
+
                              th <- myThreadId
                              mparent <- free th cont
                              case mparent of
@@ -644,12 +700,17 @@ 
     inputLoop'= do
            r<- getLine
-           if r=="end" then putMVar rexit () else do
-              let rs = breakSlash [] r
-              mapM_ (\ r -> do threadDelay 1000
-                               atomically . writeTVar  getLineRef $ Just r) rs
-              inputLoop'
+           processLine r
+           inputLoop'
 
+processLine r= do
+--   when (r=="end") $ putMVar rexit ()
+   let rs = breakSlash [] r
+   mapM_ (\ r -> if (r=="end") then putMVar rexit () else do
+                    threadDelay 1000
+                    atomically . writeTVar  getLineRef $ Just r) rs
+
+    where
     breakSlash :: [String] -> String -> [String]
     breakSlash s ""= s
     breakSlash res s=
@@ -665,18 +726,32 @@ stay=  takeMVar rexit
 
 -- | keep the main thread running, initiate the asynchronous keyboard input and execute
--- the transient computation.
+-- the transient computation. It also read a slash separated list of string that are interpreted by
+-- `option` and `input` as if they were entered by the keyboard
+keep :: TransIO a -> IO a
 keep mx = do
    forkIO $ inputLoop
    forkIO $ runTransient mx  >> return ()
+   threadDelay 100000
+   args <- getArgs
+   let path = filter (\arg -> arg !! 0 == '/') args
+   when (not (null path)) $ do
+        putStr "Executing: " >> print (head path)
+        processLine $  head path
    stay
 
+-- | same than `keep`but do not initiate the asynchronous keyboard input.
+-- Useful for debugging
+keep' :: TransIO a -> IO a
+keep' mx  = do
+   forkIO $ runTransient mx  >> return ()
+   stay
+
 -- | force the finalization of the main thread and thus, all the application
 exit :: TransientIO a
 exit= do
-  liftIO $ putStrLn "Tempus fugit: exit"
   liftIO $ putMVar rexit   True
-  return undefined
+  stop
 
 -- | alternative operator for maybe values. Used  in infix mode
 onNothing :: Monad m => m (Maybe b) -> m b -> m b
+ src/Transient/DDS.hs view
@@ -0,0 +1,215 @@+{-# LANGUAGE  ExistentialQuantification, DeriveDataTypeable #-}
+
+module Transient.DDS(distribute, cmap, reduce) where
+import Transient.Base
+import Transient.Move
+import Transient.Logged
+import Transient.Indeterminism
+
+import Control.Applicative
+import System.Random
+import Control.Monad.IO.Class
+
+import System.IO
+import Control.Monad
+import Data.Monoid
+
+import Data.Typeable
+import Data.List hiding (delete)
+import Control.Exception
+import Control.Concurrent
+import Data.Time.Clock
+
+import Data.TCache
+import Data.TCache.Defs
+--import Data.TCache.DefaultPersistence
+import Data.ByteString.Lazy.Char8 (pack,unpack)
+import Control.Monad.STM
+
+
+data DDS a= Loggable a => DDS  (TransIO [PartRef a])
+data PartRef a= Ref Node Path Save deriving (Typeable, Read, Show)
+data Partition a=  Part Node Path Save [a] deriving (Typeable,Read,Show)
+type Save= Bool
+
+instance Indexable (Partition a) where
+    key (Part _ string True _)= "PartP@"++string
+    key (Part _ string False _)= "PartT@"++string
+
+instance Loggable a => IResource (Partition a) where
+    keyResource= key
+    readResourceByKey k= if k!! 5 /= 'P' then return Nothing
+        else defaultReadByKey k >>= return . fmap ( read . unpack)
+    writeResource (s@(Part _ _ save _))= if not save then return ()
+        else defaultWrite (defPath s ++ key s) (pack$ show s)
+--instance Loggable a => Serializable (Partition a) where
+--    serialize = pack . show
+--    deserialize = read . unpack
+--    setPersist (Part _ _ persist _) =
+--      Just Persist
+--        {readByKey= if persist then defaultReadByKey else const $ return Nothing
+--        ,write    =  if persist then defaultWrite else const $  const $ return ()
+--        ,delete   = defaultDelete}
+
+
+instance Loggable a => Monoid (DDS a) where
+   mempty= DDS mempty
+   mappend (DDS ta) (DDS tb)= DDS $ ta <> tb
+
+
+
+type Path=String
+
+cmap :: Loggable b => (a -> b) -> DDS a -> DDS b
+cmap f (DDS mx)= DDS $ logged $ do
+        refs <- logged mx
+        foldl (<>) mempty $  map process refs
+
+  where
+--  process ::  Partition a -> TransIO [Partition b]
+  process  (ref@(Ref node path sav))= runAt node $  do
+              xs <- getPartitionData ref mx
+              ref <- generateRef node $ map f xs
+              return [ref]
+
+
+
+
+
+reduce' :: (Loggable b, Monoid b) => ([a] -> b) -> DDS a -> TransientIO b
+reduce' f = reduce f mappend mempty
+
+reduce ::  Loggable b => ([a] -> b) -> (b -> b -> b)-> b -> DDS a ->TransientIO b
+reduce f f2 seed (DDS mx)= logged $ do
+     refs <- logged mx
+     logged $ foldl (\ x y -> f2 <$> x <*> y)(return seed) $  map process refs
+
+     where
+
+--     process :: Partition a -> TransIO b
+     process (ref@(Ref node _ _))= runAt node $ do
+               xs <- getPartitionData ref mx
+               return $ f xs
+
+getPartitionData (Ref node path save) mx= do
+    Just (Part _ _ _ xs) <- liftIO $ atomically
+                                       $ readDBRef
+                                       $ getDBRef
+                                       $ keyResource((Part node path save undefined)
+                                                    `asTypeOf` getPartitionType mx)
+    return xs
+    where
+    getPartitionType :: TransIO [PartRef a]-> Partition a
+    getPartitionType = undefined -- type level only
+
+-- en caso de fallo de Node, se lanza un clustered en busca del path
+--   si solo uno lo tiene, se copia a otro
+--   se pone ese nodo de referencia en Part
+runAtP :: Loggable a => Node  -> (Path -> IO a) -> Path -> TransIO a
+runAtP node f uuid= do
+   r <- streamFrom node $ liftIO $ (SLast <$> f uuid) `catch` sendAnyError
+   case r of
+     SLast r -> return r
+     SError e -> do
+         nodes <-  mclustered $ search uuid
+         when(length nodes < 1) $ asyncDuplicate node uuid
+         runAtP ( head nodes) f uuid
+
+search uuid= error $ "chunk failover not yet defined. Lookin for: "++ uuid
+
+asyncDuplicate node uuid= do
+    forkTo node
+    nodes <- getNodes
+    let node'= head $ nodes \\ [node]
+    content <- liftIO $ readFile uuid
+    runAt node' $ liftIO $ writeFile uuid content
+
+sendAnyError :: SomeException -> IO (StreamData a)
+sendAnyError e= return $ SError $ show e
+
+
+distribute :: Loggable a => [a] -> DDS a
+distribute = DDS  . logged . distribute'
+
+distribute' xs=  do
+   nodes <- logged getNodes
+   let size= length xs `div` length nodes
+       xss = split size xs
+   distribute'' xss nodes
+   where
+   split n []= []
+   split n xs=
+      let (h,t)= splitAt n xs
+      in h : split n t
+
+distribute'' :: Loggable a => [[a]] -> [Node] -> TransIO[PartRef a]
+distribute'' xss nodes =
+   foldl (<>) mempty $ zipWith move nodes xss   !> show xss
+   where
+   move node xs=  runAt node $ do
+                        par <- generateRef node xs
+                        return  [par]
+
+
+
+
+textFile name= DDS $ logged $ do
+   lines <- liftIO $ liftM lines (readFile name)
+   distribute' lines
+
+--getId :: DDS a -> TransIO String
+--getId (DDS mx)= do
+--     ids <- mx
+--     let ids' = map (\(Part _  path _ _) -> path) ids
+--     return $ "DDS@"++ intercalate ":" ids'
+
+
+--fromId :: String -> DDS a
+--fromId ('D':'D':'S':'@':id)= do
+--   let ids= wordsBy (==':') id
+--   nodes <- clustered' $ mapM readDBRef ids
+--   return
+--
+--   where
+--   wordsBy :: (a -> Bool) -> [a] -> [[a]]
+--   wordsBy f s = case dropWhile f s of
+--        [] -> []
+--        x:xs -> (x:w) : wordsBy f (drop1 z)
+--            where (w,z) = break f xs
+
+
+generateRef :: Loggable a => Node -> [a] -> TransIO (PartRef a)
+generateRef node x= liftIO $ do
+       temp <- getTempName
+       let reg=  Part node temp False  x
+       atomically $ newDBRef reg
+       return $ getRef reg
+
+getRef (Part n t s x)= Ref n t s
+
+getTempName :: IO String
+getTempName=  ("DDS/" ++) <$> replicateM  5 (randomRIO ('a','z'))
+
+
+-------------- Distributed  Datasource Streams ---------
+-- | produce a stream of DDS's that can be map-reduced. Similar to spark streams.
+-- each interval of time,a new DDS is produced.
+streamDDS
+  :: (Typeable a, Show a, Read a) =>
+     Integer -> IO (StreamData a) -> DDS a
+streamDDS time io= DDS $ do
+     xs <- groupByTime time $ do
+               r <- parallel io
+               case r of
+                    SDone -> stop
+                    SLast x -> return x
+                    SMore x -> return x
+                    SError e -> error e
+     distribute'  xs
+
+
+
+
+
+
+
src/Transient/EVars.hs view
@@ -14,24 +14,26 @@ 
 newtype EVars= EVars  (IORef (M.Map Int [EventF]))  deriving Typeable
 
-data EVar a= EVar Int (IORef (Maybe a))
+data EVar a= EVar Int (IORef (Maybe a)) deriving Typeable
 
--- * Evars are event vars. `writeEVar` trigger the execution of all the continuations associated to the  `readEVar` of this variable
+
+-- | creates an EVar.
+--
+-- Evars are event vars. `writeEVar` trigger the execution of all the continuations associated to the  `readEVar` of this variable
 -- (the code that is after them) as  stack: the most recent reads are executed first.
 --
 -- It is like the publish-subscribe pattern but without inversion of control, since a readEVar can be inserted at any place in the
 -- Transient flow.
 --
--- EVars are created upstream and can be used to communicate two sub-threads of the monad. Following the Transient philosophy they 
+-- EVars are created upstream and can be used to communicate two sub-threads of the monad. Following the Transient philosophy they
 -- do not block his own thread if used with alternative operators, unlike the IORefs and TVars. And unlike STM vars, that are composable,
 -- they wait for their respective events, while TVars execute the whole expression when any variable is modified.
--- 
+--
 -- The execution continues after the writeEVar when all subscribers have been executed.
 --
 -- see https://www.fpcomplete.com/user/agocorona/publish-subscribe-variables-transient-effects-v
--- 
+--
 
--- | creates an EVar
 newEVar ::  TransientIO (EVar a)
 newEVar  = Transient $ do
    getSessionData `onNothing`  do -- initialize EVars
@@ -49,15 +51,15 @@ -- 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)= Transient $ do 
-   mr <- liftIO $ readIORef ref1
+readEVar (EVar id ref1)= Transient $ do
+   mr <- liftIO $ readIORef ref1 !> "READEVAR"
    case mr of
      Just _ -> return mr
      Nothing -> do
          cont <- getCont
          EVars ref <- getSessionData `onNothing` error "No Events context"
          map <- liftIO $ readIORef ref
-         let Just conts=  M.lookup  id map <|> Just []
+         let Just conts=  M.lookup id map <|> Just []
          liftIO $ writeIORef ref $  M.insert id (cont:conts) map
          return Nothing
 
@@ -68,12 +70,12 @@    map <- liftIO $ readIORef ref
    let Just conts = M.lookup id map <|> Just []
        len= length conts
-   runCont'  len id ref 
+   runCont'  len id ref
    liftIO $ writeIORef ref1 Nothing
    return $ Just ()
-   
+
    where
-   runCont'  0 _ _ = return () 
+   runCont'  0 _ _ = return ()
    runCont'  n id ref= do
        map <- liftIO $ readIORef ref
        let Just conts= M.lookup id map <|> Just []
@@ -82,7 +84,7 @@        runCont current
        map' <- liftIO $ readIORef ref
        let Just conts'= M.lookup id map' <|> Just []
-       if (length conts /= length conts') then return () else liftIO $ writeIORef ref $   M.insert id (nexts ++ [current]) map 
+       if (length conts /= length conts') then return () else liftIO $ writeIORef ref $   M.insert id (nexts ++ [current]) map
        runCont'  (n - 1) id ref
 
 -- | unsuscribe the last `readEVar` executed for this EVar
@@ -91,7 +93,7 @@    map <- liftIO $ readIORef ref
    let Just conts = M.lookup id map <|> Just []
    liftIO $ writeIORef ref $  M.insert id (tail conts) map
-   
+
    return $ Just ()
 
-   +
src/Transient/Indeterminism.hs view
@@ -13,7 +13,7 @@ -----------------------------------------------------------------------------
 {-# LANGUAGE BangPatterns #-}
 module Transient.Indeterminism (
-choose, choose', collect, group --, found
+choose, choose', collect, collect', group, groupByTime
 ) where
 
 import Transient.Base
@@ -26,6 +26,7 @@ import Control.Monad.State
 import Control.Concurrent.STM as STM
 import GHC.Conc
+import Data.Time.Clock
 
 
 -- | slurp a list of values and process them in parallel . To limit the number of processing
@@ -33,13 +34,18 @@ choose  ::  [a] -> TransientIO a
 choose []= empty
 choose   xs = do
-    evs <- liftIO  $ newIORef xs
-    parallel   $ do
+    evs <- liftIO $ newIORef xs
+    r <- parallel $ do
            es <- atomicModifyIORef' evs $ \es -> let !tes= tail es in (tes,es)
            case es of
-            [x]  -> return $ Left $ head es
-            x:_  -> return $ Right x
+            [x]  -> return $ SLast $ head es
+            x:_  -> return $ SMore x
+    return $ toData r
 
+toData r= case r of
+      SMore x -> x
+      SLast x -> x
+
 -- | group the output of a possible multithreaded process in groups of n elements.
 group :: Int -> TransientIO a -> TransientIO [a]
 group num proc =  do
@@ -50,9 +56,21 @@       then stop
       else liftIO $ atomicModifyIORef v $ \(n,xs) ->  ((0,[]),xs)
 
+groupByTime :: Integer -> TransientIO a -> TransientIO [a]
+groupByTime time proc =  do
+    v  <- liftIO $ newIORef (0,[])
+    t  <- liftIO getCurrentTime
+    x  <- proc
+    n  <- liftIO $ atomicModifyIORef' v $ \(n,xs) -> let !n'=n +1 in ((n', x:xs),n')
+    t' <- liftIO getCurrentTime
+    if diffUTCTime t' t < fromIntegral time
+      then stop
+      else liftIO $ atomicModifyIORef v $ \(n,xs) ->  ((0,[]),xs)
+
+
 -- | alternative definition with more parallelism
 choose' :: [a] -> TransientIO a
-choose'  xs = foldl (<|>) empty $ map (parallel . return . Left) xs
+choose'  xs = foldl (<|>) empty $ map (\x -> parallel (return (SLast x)) >>= return . toData) xs
 
 
 --newtype Collect a= Collect (MVar (Int, [a])) deriving Typeable
@@ -64,15 +82,21 @@ 
 
 -- | execute a process and get the first n solutions.
--- if the process end without finding the number of solutions requested, it return the fond ones
--- if he find the number of solutions requested, it kill the threads of the process and return
+-- if the process end without finding the number of solutions requested, it return the found ones
+-- if he find the number of solutions requested, it kill the non-free threads of the process and return
 -- 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 -> TransientIO a -> TransientIO [a]
-collect n search=  do
+collect n = collect' n 1000 0
+
+-- | search also between two time intervals. If the first interval has passed and there is no result, it stop
+-- after the second interval, it stop unconditionally. It stops as soon as it has enoug result.
+collect' :: Int -> NominalDiffTime -> NominalDiffTime -> TransientIO a -> TransientIO [a]
+collect' n t1 t2 search=  do
   rv <- liftIO $ atomically $ newTVar (0,[]) !> "NEWMVAR"
   endflag <- liftIO $ newTVarIO False
   st <- get
+  t <- liftIO getCurrentTime
   let any1 = do
         r <- search   !> "ANY"
         liftIO $ atomically $ do
@@ -80,16 +104,16 @@             writeTVar  rv (n1+1,r:rs) !> "MODIFY"
         stop
 
-      detect= freeThreads $ do
-          xs <- async $ do
-             threadDelay 1000 -- to allow some activity before monitoring it
-             atomically $ do
-                (n',xs) <- readTVar rv
-                ns <- readTVar $ children st
-
-                if (n > 0 && n' >= n) ||  null ns  !> show (n,n') !> (show $ length ns)
-                  then return xs
-                  else retry
+      monitor= freeThreads $ do
+          xs <- async $ atomically $
+                          do (n', xs) <- readTVar rv
+                             ns <- readTVar $ children st
+                             t' <- unsafeIOToSTM getCurrentTime
+                             if
+                               (n > 0 && n' >= n) ||
+                                 (null ns && (diffUTCTime t' t > t1)) || -- !> show (n, n', length ns)
+                                 (t2 > 0 && diffUTCTime t' t > t2)
+                               then return xs else retry
 
           th <- liftIO $ myThreadId !> "KILL"
           stnow <- get
@@ -97,5 +121,8 @@           liftIO $ addThread st stnow
           return  xs
 
-  (any1 >> stop)  <|> detect
+  monitor <|> any1
+
+
+
 
src/Transient/Logged.hs view
@@ -11,7 +11,7 @@ -- |
 --
 -----------------------------------------------------------------------------
-{-# LANGUAGE  ExistentialQuantification #-}
+{-# LANGUAGE  ExistentialQuantification, FlexibleInstances, UndecidableInstances #-}
 module Transient.Logged  where
 
 import Data.Typeable
@@ -20,6 +20,17 @@ import Control.Applicative
 import Control.Monad.IO.Class
 
+
+--newtype Logged m a =  Logged {runLogged :: m a}
+--
+--data RLogged= forall a.(Read a, Show a) => RLogged  a
+--
+--instance Monad m => Monad (Logged m)  where
+--   return  x=  Logged $ return x
+--   Logged x >>= f =  Logged $ do
+--         r <- x
+--         runLogged $ f r
+
 --data IDynamic= IDyns String | forall a.(Read a, Show a,Typeable a) => IDynamic a
 
 --instance Show IDynamic where
@@ -29,6 +40,8 @@ --instance Read IDynamic where
 --  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec n str
 
+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
@@ -43,7 +56,7 @@ 
 
 
--- | write the result of the computation in the log and return it.
+-- | write the result of the computation in  the log and return it.
 -- but if there is data in the internal log, it read the data from the log and
 -- do not execute the computation.
 --
src/Transient/Move.hs view
@@ -11,15 +11,17 @@ -- | see <https://www.fpcomplete.com/user/agocorona/moving-haskell-processes-between-nodes-transient-effects-iv>
 -----------------------------------------------------------------------------
 {-# LANGUAGE DeriveDataTypeable , ExistentialQuantification
-    ,ScopedTypeVariables, StandaloneDeriving #-}
+    ,ScopedTypeVariables, StandaloneDeriving, RecordWildCards #-}
 module Transient.Move where
 import Transient.Base
 import Transient.Logged
 import Data.Typeable
 import Control.Applicative
 import Network
-import Network.HTTP
+
+
 import Control.Monad.IO.Class
+import Control.Monad.State
 import System.IO
 import Control.Exception
 import Data.Maybe
@@ -30,16 +32,28 @@ import Network.Info
 import System.IO.Unsafe
 import Control.Concurrent.STM as STM
+import Control.Concurrent.MVar
+
 import Data.Monoid
 import qualified Data.Map as M
-import Data.List (nub,(\\))
+import Data.List (nub,(\\),find)
 import Data.IORef
 
+import qualified Network.Socket as NS
+import qualified Network.BSD as BSD
 
+
+import qualified Data.ByteString.Char8 as BS
+import System.IO
+
+
+import Control.Concurrent
+
+
 -- | install in a remote node a haskell package with an executable transient service initialized with `listen`
 -- the package, the git repository and the main exectable must have the same name
-installService node port servport package= do
-  beamTo node port
+installService (node@(Node _ port _)) servport package= do
+  beamTo node
   liftIO $ do
      let packagename= name package
      exist <- doesDirectoryExist  packagename
@@ -47,108 +61,204 @@          runCommand $ "git clone "++ package
          runCommand $ "cd "++ packagename
          runCommand "cabal install"
-         createProcess $ shell $ "./dist/build/"++ packagename++"/"++packagename
+         return ()
+     createProcess $ shell $ "./dist/build/"++ packagename++"/"++packagename
                                        ++ " " ++ show port
-         return()
+     return()
   where
   name path=
      let x= dropWhile (/= '/') path
-     in if x== "" then tail path else name $ tail    x
+     in if x== "" then tail path else name $ tail x
 
 -- | continue the execution in a new node
 -- all the previous actions from `listen` to this statement must have been logged
-beamTo :: HostName -> PortID -> TransientIO ()
-beamTo host port= do
+beamTo :: Node -> TransientIO ()
+beamTo node =  do
   Log rec log _ <- getSData <|> return (Log False [][])
   if rec then return () else do
-      h <- liftIO $ connectTo host port
-      liftIO $ hSetBuffering h LineBuffering
-      liftIO $ hPutStrLn h (show $ reverse log) >> hFlush h
-      liftIO $ hClose h
-      delSData h
+      Connection _ bufSize <- getSData <|> return (Connection Nothing 8192)
+      h <-  assign bufSize node
+      liftIO $ hPutStrLn h (show $ SMore $ reverse log) >> hFlush h
+      release node h
+      let log'= WaitRemote: log
+      setSData $ Log rec log' log'
       stop
 
 -- | execute in the remote node a process with the same execution state
 -- all the previous actions from `listen` to this statement must have been logged
-forkTo  :: HostName -> PortID -> TransientIO ()
-forkTo host port= do
+forkTo  :: Node -> TransientIO ()
+forkTo node= do
   Log rec log _<- getSData <|> return (Log False [][])
   if rec then return () else do
-      h <- liftIO $ connectTo host port
-      liftIO $ hSetBuffering h LineBuffering
-      liftIO $ hPutStrLn h (show $ reverse log)  >> hFlush h
-      liftIO $ hClose h
-      delSData h
+      Connection _ bufSize <- getSData <|> return (Connection Nothing 8192)
+      h <-assign bufSize node
+      liftIO $ hPutStrLn h (show $ SMore $ reverse log)  >> hFlush h
+      release node h
 
 -- | executes an action in another node.
+-- All the previous actions from `listen` to this statement must have been logged
+callTo :: Loggable a => Node -> TransIO a -> TransIO a
+callTo n p = streamFrom n (SMore <$> p) >>= \(SMore x) -> return x
+
+
+-- | synonymous of `callTo`
 -- all the previous actions from `listen` to this statement must have been logged
-callTo :: (Show a, Read a,Typeable a) => HostName -> PortID -> TransIO a -> TransIO a
-callTo host port remoteProc= logged $ Transient $ do
---      liftIO $ print "callto"
+runAt :: Loggable a => Node -> TransIO a -> TransIO a
+runAt= callTo
+
+-- | `callTo` can stream data but can not inform the receiving process about the finalization. This call
+-- does it.
+--
+-- All the previous actions from `listen` to this statement must have been logged
+streamFrom :: Loggable a => Node -> TransIO (StreamData a) -> TransIO (StreamData a)
+streamFrom node remoteProc= logged $ Transient $ do
       Log rec log fulLog <- getSessionData `onNothing` return (Log False [][])
       if rec
          then
           runTrans $ do
+            rnum <- liftIO $ newMVar (0 :: Int)
+            Connection (Just (_, h, sock, blocked)) _ <- getSData  <|> error "callTo: no hander"
+            r <- remoteProc                       !> "executing remoteProc" !> "CALLTO REMOTE" -- LOg="++ show fulLog
+            n <- liftIO $ do
+--                modifyMVar_ rnum $ \n -> return (n+1)
+                withMVar blocked $ const $ hPutStrLn   h (show r)  `catch` (\(e::SomeException) -> sClose sock)
+                 -- !> "sent response, HANDLE="++ show h
+--                modifyMVar rnum $ \n -> return (n-1,n)
 
-               Connection port  h sock <- getSData <|> error "callto: no hander"
-               r <- remoteProc !> "executing remoteProc" !> "CALLTO REMOTE" -- LOg="++ show fulLog
-               liftIO $ hPutStrLn h (show r) --  `catch` (\(e::SomeException) -> sClose sock)
-                -- !> "sent response, HANDLE="++ show h
-               setSData WasRemote
-               stop
+ --           adjustSenderThreads n
 
+            setSData WasRemote
+            stop
 
          else do
+            Connection _ bufSize <- getSessionData `onNothing` return (Connection Nothing 8192)
+            h <- assign bufSize node
+            liftIO $ hSetBuffering h LineBuffering
+            liftIO $ hPutStrLn h ( show $ SLast $ reverse fulLog) {- >> hFlush h -} !> "CALLTO LOCAL" -- send "++ show  log
 
-            h <- liftIO $ connectTo host port
-            liftIO $ hPutStrLn h (show $ reverse fulLog) >> hFlush h !> "CALLTO LOCAL" -- send "++ show  log
+
             let log'= WaitRemote:tail log
             setSessionData $ Log rec log' log'
-            runTrans $ waitEvents $ do -- local side
-                   liftIO $ hSetBuffering h LineBuffering
-                   s <- hGetLine h
---                   hClose h
+            runTrans $ do
+              r<- parallel $ do -- local side
+                   r <- readHandler h
 
-                   let r = read s
+                   case r of
+                        SDone -> release node h >> return SDone
+                        other -> return other
 
-                   return r   !> "read: " ++ s ++" response type= "++show( typeOf r)
+--              adjustRecThreads h
+              case r of
+                SDone -> empty
+                other  -> return other
 
+--      where
+--      adjustRecThreads h= do
+--          b <- liftIO $ hWaitForInput  h 1
+--          addThreads' $ if b then 1 else 0
+--          liftIO $ putStrLn $ "REC "++ show (case b of True -> "INC" ; _ -> "DEC")
+--
+--      adjustSenderThreads n
+--         | n > 2 = addThreads' (-1)  >> liftIO (putStrLn ("SEND DEC"))
+--         | n==0 = addThreads' 1  >> liftIO (putStrLn ("SEND INC"))
+--         | otherwise= return () >> liftIO(myThreadId >>= \th -> (putStrLn ("SEND "++ show th)))
+
+
 -- | A connectionless version of callTo for long running remote calls
-callTo' :: (Show a, Read a,Typeable a) => HostName -> PortID -> TransIO a -> TransIO a
-callTo' rhost rport remoteProc= logged $ do
-    (host,port) <- getMyNode
-    logged $ beamTo rhost rport
+callTo' :: (Show a, Read a,Typeable a) => Node -> TransIO a -> TransIO a
+callTo' node remoteProc= logged $ do
+    mynode <- logged getMyNode
+    beamTo node
     r <- logged remoteProc
-    logged $ beamTo host port
+    beamTo mynode
     return r
 
-data Connection= Connection PortID Handle Socket deriving Typeable
+type Blocked= MVar ()
+type BuffSize = Int
+data Connection= Connection (Maybe(PortID, Handle, Socket, Blocked)) BuffSize
+                  deriving Typeable
 
+setBufSize :: Int -> TransIO ()
+setBufSize size= Transient $ do
+   Connection c _ <- getSessionData `onNothing` return (Connection Nothing  size)
+   setSessionData $ Connection c size
+   return $ Just ()
+
+
+readHandler h= do
+    line <- hGetLine h -- {-  readIORef leftover <> -} unsafeInterleaveIO (hGetLine h)
+--    liftIO $ print (line, show h)
+    let [(v,left)]= readsPrec 0 line
+--    length v `seq` writeIORef leftover left
+    return  v
+
+  `catch` (\(e::SomeException) -> do
+      hClose h
+      liftIO $ do
+         putStr "readHandler: "
+         print e
+         return SDone)
+   where
+--   hGetLine' h= do
+
+
+
+connectTo' bufSize hostname (PortNumber port) = do
+    proto <- BSD.getProtocolNumber "tcp"
+    bracketOnError
+        (NS.socket NS.AF_INET NS.Stream proto)
+        (sClose)  -- only done if there's an error
+        (\sock -> do
+          NS.setSocketOption sock NS.RecvBuffer bufSize
+          NS.setSocketOption sock NS.SendBuffer bufSize
+          he <- BSD.getHostByName hostname
+          NS.connect sock (NS.SockAddrInet port (BSD.hostAddress he))
+
+          NS.socketToHandle sock ReadWriteMode
+        )
+
 -- | Wait for messages and replay the rest of the monadic sequence with the log received.
-listen :: PortID ->  TransIO ()
-listen  port = do
-       setSData $ Log False [] []
-       sock <- liftIO $ withSocketsDo $ listenOn  port
+listen ::  Node ->  TransIO ()
+listen  (Node _  port _) = do
+   addThreads 1
+   setSData $ Log False [] []
+   Connection _ bufSize <- getSData <|> return (Connection Nothing 8192)
+   sock <- liftIO $ withSocketsDo $ listenOn  port
+   liftIO $ do NS.setSocketOption sock NS.RecvBuffer bufSize
+               NS.setSocketOption sock NS.SendBuffer bufSize
+   SMore(h,host,port1) <- parallel $ SMore <$> accept sock
+                          `catch` (\(e::SomeException) -> print "socket exception" >> sClose sock >> throw e)
 
-       (h,host,port1) <- parallel $ Right <$> accept sock
-                          `catch` (\(e::SomeException) -> sClose sock >> throw e)
+   setSData $ Connection (Just (port, h, sock, unsafePerformIO $ newMVar ())) bufSize -- !> "setdata port=" ++ show port
 
-       liftIO $  hSetBuffering h LineBuffering  -- !> "LISTEN in "++ show (h,host,port1)
+   liftIO $  hSetBuffering h LineBuffering -- !> "LISTEN in "++ show (h,host,port1)
 
-       slog <- Transient $ liftIO $ (Just <$> hGetLine  h)
-                          `catch` (\(e::SomeException) -> print "ERR" >>  return Nothing)
+   mlog <- parallel $ readHandler h
 
-       setSData $ Connection port h sock  -- !> "setdata port=" ++ show port
+   case  mlog  of
+         SError e -> do
+             liftIO $ do
+                hClose h
+                putStr "listen: "
+                print e
+             stop
 
-       let log= read slog   -- !> "read1 " ++ slog
-       setSData $ Log True log (reverse log)
+         SDone -> liftIO (hClose h) >> stop
+         SMore log -> setSData $ Log True log (reverse log)
+         SLast log -> setSData $ Log True log (reverse log)
 
 
+
+
+
+
+
+
 -- | init a Transient process in a interactive as well as in a replay mode.
 -- It is intended for twin processes that interact among them in different nodes.
-beamInit :: PortID -> TransIO a -> IO b
-beamInit port program=  keep $ do
-    listen port   <|> return ()
+beamInit :: Node  -> TransIO a -> IO a
+beamInit  node program=  keep $ do
+    listen  node   <|> return ()
     program
 
 
@@ -161,13 +271,59 @@ deriving instance Read PortID
 deriving instance Typeable PortID
 
+
+
+data Pool=  Pool{free :: [Handle], pending :: Int}
+
+data Node= Node{host :: HostName, port :: PortID, connection :: IORef Pool} deriving Typeable
+
+release (Node h p rpool) hand= liftIO $ do
+  mhs <- atomicModifyIORef rpool $
+            \(Pool hs pend) ->
+               if pend==0
+                 then (Pool [] 0,Just hs)
+                 else (Pool (hand:hs) pend,Nothing)
+  case mhs of
+    Nothing -> return ()
+    Just hs  -> mapM_ hClose hs
+
+
+assign bufSize (Node h p pool)= liftIO $ do
+    mh <- atomicModifyIORef pool $
+            \(Pool hs p) ->  if null hs then (Pool hs p, Nothing)
+                                        else (Pool (tail hs) p, Just(head hs)) !> "REUSED"
+    case mh of
+      Just handle -> liftIO (putStrLn "REUSED!") >> return handle
+      Nothing -> liftIO $ do
+                  h <- connectTo' bufSize h p     !>  "REOPEN"
+                  hSetBuffering h LineBuffering
+                  return h
+
+
+
+
 -- * Level 2: connections node lists and operations with the node list
 
-data Node= Node{host :: HostName, port :: PortID, connection :: Maybe(Handle,Socket,HostName,PortID)} deriving (Eq,Typeable)
 
+{-# NOINLINE emptyPool #-}
+emptyPool :: MonadIO m => m (IORef Pool)
+emptyPool= liftIO $ newIORef $ Pool [] 0
+
+createNode :: HostName -> Integer -> Node
+createNode h p= Node h ( PortNumber $ fromInteger p) (unsafePerformIO emptyPool)
+
+instance Eq Node where
+    Node h p _ ==Node h' p' _= h==h' && p==p'
+
 instance Show Node where show (Node h p _)= show (h,p)
-instance Read Node where readsPrec _ s= let [((h,p),s')]= readsPrec 0 s in [((Node h p Nothing),s')]
 
+instance Read Node where
+     readsPrec _ s=
+          let [((h,p),s')]= readsPrec 0 s
+          in [(Node h p empty,s')]
+          where
+          empty= unsafePerformIO  emptyPool
+
 nodeList :: TVar  [Node]
 nodeList = unsafePerformIO $ newTVarIO []
 
@@ -175,17 +331,24 @@ 
 myNode= unsafePerformIO $ newIORef Nothing
 
-setMyNode h p= liftIO $ writeIORef  myNode $ Just (h,p)
+setMyNode node= liftIO $ writeIORef  myNode $ Just node
 getMyNode= Transient $ liftIO $ readIORef myNode
 
-getNodes :: TransIO [Node]
-getNodes  = Transient $ Just <$> (liftIO $ atomically $ readTVar  nodeList)
+getNodes :: MonadIO m => m [Node]
+getNodes  = liftIO $ atomically $ readTVar  nodeList
 
-addNodes   nodes= Transient . liftIO . atomically $ do
+addNodes :: MonadIO m => [Node] -> m ()
+addNodes   nodes=  liftIO . atomically $ do
   prevnodes <- readTVar nodeList
-  writeTVar nodeList $ nub $ prevnodes ++  nodes
-  return $ Just ()
+  writeTVar nodeList $ nub $ nodes ++ prevnodes
 
+shuffleNodes :: MonadIO m => m [Node]
+shuffleNodes=  liftIO . atomically $ do
+  nodes <- readTVar nodeList
+  let nodes'= tail nodes ++ [head nodes]
+  writeTVar nodeList nodes'
+  return nodes'
+
 --getInterfaces :: TransIO TransIO HostName
 --getInterfaces= do
 --   host <- logged $ do
@@ -196,32 +359,56 @@ --      return $ show . ipv4 $ ifs !! ind
 
 
--- | execute a Transient action in each of the nodes connected. The results are aggregated with `mappend`
-clustered :: (Typeable a, Show a, Read a) => Monoid a => TransIO a -> TransIO a
+-- | execute a Transient action in each of the nodes connected.
+--
+-- The response of each node is returned and processed by the rest of the procedure.
+-- By default, the response is processed in a new thread. To restrict the number of threads
+-- use the thread control primitives.
+--
+-- this snippet receive a message from each of the simulated nodes:
+-- > main = keep $ do
+-- >    let nodes= map createLocalNode [2000..2005]
+-- >    addNodes nodes
+-- >    (foldl (<|>) empty $ map listen nodes) <|> return ()
+-- >
+-- >    r <- clustered $ do
+-- >               Connection (Just(PortNumber port, _, _, _)) _ <- getSData
+-- >               return $ "hi from " ++ show port++ "\n"
+-- >    liftIO $ putStrLn r
+-- >    where
+-- >    createLocalNode n= createNode "localhost" (PortNumber n)
+clustered :: Loggable a  => TransIO a -> TransIO a
 clustered proc= logged $ do
      nodes <- step getNodes
-     logged $ foldr (<>) mempty $ map (\(Node h p _) -> callTo h p proc) nodes !> "fold"
+     logged $ foldr (<|>) empty $ map (\node -> callTo node proc) nodes !> "fold"
 
 -- | a connectionless version of clustered for long running remote computations. Not tested
 clustered' proc= logged $ do
+     nodes <-  getNodes
+     logged $ mapM (\node -> callTo' node proc) $ nodes
+
+-- A variant of clustered that wait for all the responses and `mappend` them
+mclustered :: (Monoid a, Loggable a)  => TransIO a -> TransIO a
+mclustered proc= logged $ do
      nodes <- step getNodes
-     logged $ mapM (\(Node h p _) -> callTo' h p proc) $ nodes
+     logged $ foldr (<>) mempty $ map (\node -> callTo node proc) nodes !> "fold"
 
--- | Connect to a new node to another. The other node will notify about this connection to
--- all the nodes connected to him. the new connected node will receive the list of connected nodes
--- the nodes will be updated with this list. it can be retrieved with `getNodes`
-connect ::   HostName ->  PortID ->  HostName ->  PortID -> TransientIO ()
-connect host  port   remotehost remoteport=  do
-    listen port <|> return ()
+-- | Initiates the transient monad, initialize it as a new node (first parameter) and connect it
+-- to an existing node (second parameter).
+-- The other node will notify about this connection to
+-- all the nodes connected to him. this new connected node will receive the list of nodes
+-- the local list of nodes then is updated with this list. it can be retrieved with `getNodes`
+connect ::  Node ->  Node -> TransientIO ()
+connect  (node@(Node h port _))  remotenode=  do
+    listen node <|> return ()
     logged $ do
-        let n= Node host port Nothing
         logged $ do
-             setMyNode host port
-             addNodes [n]
-             liftIO $ putStrLn $ "connecting to: "++ show (remotehost,remoteport)
-        newnode <- logged $ return n -- must pass my node the remote node or else it will use his own
+             setMyNode node
+             addNodes [node]
+             liftIO $ putStrLn $ "connecting to: "++ show remotenode
+        newnode <- logged $ return node -- must pass my node the remote node or else it will use his own
         port <- logged $ return port
-        nodes <- callTo remotehost remoteport   $ do
+        nodes <- callTo remotenode $ do
                    clustered $  addNodes [newnode]
                    r <- getNodes
                    liftIO $ putStrLn $ "Connected to modes: " ++ show r
+ src/Transient/Stream/Resource.hs view
@@ -0,0 +1,119 @@+-----------------------------------------------------------------------------
+--
+-- Module      :  Transient.Stream.Resource
+-- Copyright   :
+-- License     :  GPL-3
+--
+-- Maintainer  :  agocorona@gmail.com
+-- Stability   :
+-- Portability :
+--
+-- |
+--
+-----------------------------------------------------------------------------
+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable  #-}
+module Transient.Stream.Resource(sourceFile, sinkFile, process, finish, onFinish) where
+
+
+import Transient.Base hiding (loop)
+import Transient.EVars
+import Control.Exception
+import Control.Applicative
+import Control.Monad.IO.Class
+import Data.Typeable
+import Data.Char
+import System.IO
+
+
+
+
+
+
+-- | Stream the input to a file
+sinkFile :: TransIO String -> String -> TransIO ()
+sinkFile input file= process input (openFile file WriteMode)  hClose' hPutStrLn'
+  where
+  hClose' h= putStr "closing " >> putStrLn file >> hClose h
+  hPutStrLn' h  x= liftIO $ (SMore <$>  hPutStrLn h x)
+                  `catch` (\(e::SomeException)-> return $ SError (show e))
+
+-- | slurp input from a file a line at a time. It creates as much threads as possible.
+-- to allow single threaded processing, use it with `threads 0`
+sourceFile :: String -> TransIO String
+sourceFile file= process (return ()) (openFile file ReadMode)  hClose' read'
+      where
+      hGetLine' h= (SMore <$> hGetLine h)
+                   `catch` (\(e::SomeException)-> return $ SError(show e))
+      read' h _ =  parallel $ hGetLine' h
+
+
+      hClose' h= putStr "closing ">> putStrLn file >> hClose h
+
+-- | is the general operation for processing a streamed input, with opening  resources before
+-- processing and closing them when finish is called.  The process statements suscribe to the
+-- EVar `Finish`.
+--
+-- when this variable is updated, the close section is called.
+--
+-- When the processing return `SDone` or `SError`, the `Finish` variable is updated so all the
+-- subscribed code that close the resources are executed.
+process
+  :: TransIO a
+     -> IO handle
+     -> (handle -> IO ())
+     -> (handle -> a -> TransIO (StreamData b))
+     -> TransIO b
+process input open close process=do
+   mh <- liftIO $ (Right <$> open)  `catch` (\(e::SomeException)-> return $ Left e)
+   case mh of
+      Left e -> liftIO (putStr "process: " >> print e) >> finish  >> stop
+      Right h -> do
+       onFinish (liftIO (close h) >> killChilds >> stop) <|> return()
+       some <- input
+       process' h  some
+       where
+       process' h something = do
+           v <- process h  something
+           checkFinalize v
+
+
+
+checkFinalize v=
+           case v of
+              SDone ->  finish  >> stop
+              SLast x ->  finish >> return x
+              SError e -> liftIO ( putStrLn e) >> finish  >> stop
+              SMore x -> return x
+
+
+
+newtype Finish= Finish (EVar Bool) deriving Typeable
+
+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 :: TransIO () -> TransIO a
+onFinish  close= do
+       Finish finish <- getSData <|> initFinish
+       readEVar finish
+       close
+       stop
+
+-- | trigger the event for the closing of all the resources
+finish :: TransIO ()
+finish = do
+    liftIO $ putStrLn "finish Called"
+    Finish finish <- getSData
+    writeEVar finish True
+
+
+
+
+
+
+
transient.cabal view
@@ -1,53 +1,53 @@ name: transient
-synopsis: A monad for extensible effects and primitives for unrestricted composability of applications
-homepage: http://www.fpcomplete.com/user/agocorona
-bug-reports: https://github.com/agocorona/transient/issues
-version: 0.1.0.4
+version: 0.1.0.8
 cabal-version: >=1.10
 build-type: Simple
 license: GPL-3
 license-file: LICENSE
 maintainer: agocorona@gmail.com
+homepage: http://www.fpcomplete.com/user/agocorona
+bug-reports: https://github.com/agocorona/transient/issues
+synopsis: A monad for extensible effects and primitives for unrestricted composability of applications
+description: see <http://github.com/agocorona/transient>
 category: Control
 author: Alberto G. Corona
-description:
-     see <http://github.com/agocorona/transient>
-
 data-dir: ""
 
-library
-    build-depends: base -any, mtl -any, random -any, containers -any,
-                   directory -any, filepath -any, stm -any, HTTP -any, network -any,
-                   transformers -any, process -any, network-info -any
+source-repository head
+    type: git
+    location: https://github.com/agocorona/transient
 
-    exposed-modules: Transient.Indeterminism Transient.Base Transient.EVars
-                     Transient.Backtrack Transient.Move Transient.Logged
+library
+    build-depends: base  >4 && <5 , mtl , random , containers ,
+                   directory , filepath , stm , HTTP , network ,
+                   transformers , process , network-info ,
+                   bytestring , time , TCache
+    exposed-modules: Transient.DDS Transient.Indeterminism
+                     Transient.Base Transient.EVars Transient.Backtrack Transient.Move
+                     Transient.Logged Transient.Stream.Resource
     exposed: True
     buildable: True
     default-language: Haskell2010
     hs-source-dirs: src .
-    other-modules:
 
-executable transient
-    build-depends: base >4 && <5, mtl -any, random -any, containers -any,
-                   directory -any, filepath -any, stm -any, HTTP -any, network -any,
-                   transformers -any, transient -any
-    main-is: Main.hs
-    buildable: True
-    default-language: Haskell2010
-    hs-source-dirs: .
-    other-modules:
+--executable transient
+--    build-depends: base >4 && <5, mtl , random ,
+--                   containers , directory , filepath , stm ,
+--                   HTTP , network , transformers , transient ,
+--                   bytestring
+--    main-is: examples/Main.hs
+--    buildable: True
+--    default-language: Haskell2010
+--    hs-source-dirs: .
+--    other-modules:
+--
+--executable distributed
+--    build-depends: base , mtl , random , containers ,
+--                   directory , filepath , stm , HTTP , network ,
+--                   transformers , transient , bytestring
+--    main-is: examples/distributedExamples.hs
+--    buildable: True
+--    default-language: Haskell2010
+--    hs-source-dirs: .
 
-executable move
-    build-depends: base -any, mtl -any, random -any, containers -any,
-                   directory -any, filepath -any, stm -any, HTTP -any, network -any,
-                   transformers -any, transient -any
-    main-is: move.hs
-    buildable: True
-    default-language: Haskell2010
-    hs-source-dirs: .
-    other-modules:
 
-source-repository head
-  type:     git
-  location: https://github.com/agocorona/transient