{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
--
-- Module      :  Base
-- Copyright   :
-- License     :  MIT
--
-- Maintainer  :  agocorona@gmail.com
-- Stability   :
-- Portability :
--
-- | Transient provides high level concurrency allowing you to do concurrent
-- processing without requiring any knowledge of threads or synchronization.
-- From the programmer's perspective, the programming model is single threaded.
-- Concurrent tasks are created and composed seamlessly resulting in highly
-- modular and composable concurrent programs.  Transient has diverse
-- applications from simple concurrent applications to massively parallel and
-- distributed map-reduce problems.  If you are considering Apache Spark or
-- Cloud Haskell then transient might be a simpler yet better solution for you
-- (see
-- <https://github.com/transient-haskell/transient-universe transient-universe>).
-- Transient makes it easy to write composable event driven reactive UI
-- applications. For example, <https://hackage.haskell.org/package/axiom Axiom>
-- is a transient based unified client and server side framework that provides
-- a better programming model and composability compared to frameworks like
-- ReactJS.
--
-- = Overview
--
-- The 'TransientIO' monad allows you to:
--
-- * Split a problem into concurrent task sets
-- * Compose concurrent task sets using non-determinism
-- * Collect and combine results of concurrent tasks
--
-- You can think of 'TransientIO' as a concurrent list transformer monad with
-- many other features added on top e.g. backtracking, logging and recovery to
-- move computations across machines for distributed processing.
--
-- == Non-determinism
--
-- In its non-concurrent form, the 'TransientIO' monad behaves exactly like a
-- <http://hackage.haskell.org/package/list-transformer list transformer monad>.
-- It is like a list whose elements are generated using IO effects. It composes
-- in the same way as a list monad. Let's see an example:
--
-- @
-- import Control.Concurrent (threadDelay)
-- import Control.Monad.IO.Class (liftIO)
-- import System.Random (randomIO)
-- import Transient.Base (keep, threads, waitEvents)
--
-- main = keep $ threads 0 $ do
--     x <- waitEvents (randomIO :: IO Int)
--     liftIO $ threadDelay 1000000
--     liftIO $ putStrLn $ show x
-- @
--
-- 'keep' runs the 'TransientIO' monad. The 'threads' primitive limits the
-- number of threads to force non-concurrent operation.  The 'waitEvents'
-- primitive generates values (list elements) in a loop using the 'randomIO' IO
-- action.  The above code behaves like a list monad as if we are drawing
-- elements from a list generated by 'waitEvents'.  The sequence of actions
-- following 'waitEvents' is executed for each element of the list. We see a
-- random value printed on the screen every second. As you can see this
-- behavior is identical to a list transformer monad.
--
-- == Concurrency
--
-- 'TransientIO' monad is a concurrent list transformer i.e. each element of
-- the generated list can be processed concurrently.  In the previous example
-- if we change the number of threads to 10 we can see concurrency in action:
--
-- @
-- ...
-- main = keep $ threads 10 $ do
-- ...
-- @
--
-- Now each element of the list is processed concurrently in a separate thread,
-- up to 10 threads are used. Therefore we see 10 results printed every second
-- instead of 1 in the previous version.
--
-- In the above examples the list elements are generated using a synchronous IO
-- action.  These elements can also be asynchronous events, for example an
-- interactive user input.  In transient, the elements of the list are known as
-- tasks.  The tasks terminology is general and intuitive in the context of
-- transient as tasks can be triggered by asynchronous events and multiple of
-- them can run simultaneously in an unordered fashion.
--
-- == Composing Tasks
--
-- The type @TransientIO a@ represents a /task set/ with each task in
-- the set returning a value of type @a@.  A task set could be /finite/ or
-- /infinite/; multiple tasks could run simultaneously.  The absence of a task,
-- a void task set or failure is denoted by a special value 'empty' in an
-- 'Alternative' composition, or the 'stop' primitive in a monadic composition.
-- In the transient programming model the programmer thinks in terms of tasks
-- and composes tasks. Whether the tasks run synchronously or concurrently does
-- not matter; concurrency is hidden from the programmer for the most part. In
-- the previous example the code written for a single threaded list transformer
-- works concurrently as well.
--
-- We have already seen that the 'Monad' instance provides a way to compose the
-- tasks in a sequential, non-deterministic and concurrent manner.  When a void
-- task set is encountered, the monad stops processing any further computations
-- as we have nothing to do.  The following example does not generate any
-- output after "stop here":
--
-- @
-- main = keep $ threads 0 $ do
--     x <- waitEvents (randomIO :: IO Int)
--     liftIO $ threadDelay 1000000
--     liftIO $ putStrLn $ "stop here"
--     stop
--     liftIO $ putStrLn $ show x
-- @
--
-- When a task creation primitive creates a task concurrently in a new thread
-- (e.g.  'waitEvents'), it returns a void task set in the current thread
-- making it stop further processing. However, processing resumes from the same
-- point onwards with the same state in the new task threads as and when they
-- are created; as if the current thread along with its state has branched into
-- multiple threads, one for each new task. In the following example you can
-- see that the thread id changes after the 'waitEvents' call:
--
-- @
-- main = keep $ threads 1 $ do
--     mainThread <- liftIO myThreadId
--     liftIO $ putStrLn $ "Main thread: " ++ show mainThread
--     x <- waitEvents (randomIO :: IO Int)
--
--     liftIO $ threadDelay 1000000
--     evThread <- liftIO myThreadId
--     liftIO $ putStrLn $ "Event thread: " ++ show evThread
-- @
--
-- Note that if we use @threads 0@ then the new task thread is the same as the
-- main thread because 'waitEvents' falls back to synchronous non-concurrent
-- mode, and therefore returns a non void task set.
--
-- In an 'Alternative' composition, when a computation results in 'empty'
-- the next alternative is tried. When a task creation primitive creates a
-- concurrent task, it returns 'empty' allowing tasks to run concurrently when
-- composed with the '<|>' combinator. The following example combines two
-- single concurrent tasks generated by 'async':
--
-- @
-- main = keep $ do
--     x <- event 1 \<|\> event 2
--     liftIO $ putStrLn $ show x
--     where event n = async (return n :: IO Int)
-- @
--
-- Note that availability of threads can impact the behavior of an application.
-- An infinite task set generator (e.g. 'waitEvents' or 'sample') running
-- synchronously (due to lack of threads) can block all other computations in
-- an 'Alternative' composition.  The following example does not trigger the
-- 'async' task unless we increase the number of threads to make 'waitEvents'
-- asynchronous:
--
-- @
-- main = keep $ threads 0 $ do
--     x <- waitEvents (randomIO :: IO Int) \<|\> async (return 0 :: IO Int)
--     liftIO $ threadDelay 1000000
--     liftIO $ putStrLn $ show x
-- @
--
-- == Parallel Map Reduce
--
-- The following example uses 'choose' to send the items in a list to parallel
-- tasks for squaring and then folds the results of those tasks using 'collect'.
--
-- @
-- import Control.Monad.IO.Class (liftIO)
-- import Data.List (sum)
-- import Transient.Base (keep)
-- import Transient.Indeterminism (choose, collect)
--
-- main = keep $ do
--     collect 100 squares >>= liftIO . putStrLn . show . sum
--     where
--         squares = do
--             x <- choose [1..100]
--             return (x * x)
-- @
--
-- == State Isolation
--
-- State is inherited but never shared.  A transient application is written as
-- a composition of task sets.  New concurrent tasks can be triggered from
-- inside a task.  A new task inherits the state of the monad at the point
-- where it got started. However, the state of a task is always completely
-- isolated from other tasks irrespective of whether it is started in a new
-- thread or not.  The state is referentially transparent i.e. any changes to
-- the state creates a new copy of the state.  Therefore a programmer does not
-- have to worry about synchronization or unintended side effects.
--
-- The monad starts with an empty state. At any point you can add ('setData'),
-- retrieve ('getSData') or delete ('delData') a data item to or from the
-- current state.  Creation of a task /branches/ the computation, inheriting
-- the previous state, and collapsing (e.g. 'collect') discards the state of
-- the tasks being collapsed. If you want to use the state in the results you
-- will have to pass it as part of the results of the tasks.
--
-- = Reactive Applications
--
-- A popular model to handle asynchronous events in imperative languages is the
-- callback model.  The control flow of the program is driven by events and
-- callbacks; callbacks are event handlers that are hooked into the event
-- generation code and are invoked every time an event happens. This model
-- makes the overall control flow hard to understand resulting into a "callback
-- hell" because the logic is distributed across various isolated callback
-- handlers, and many different event threads work on the same global state.
--
-- Transient provides a better programming model for reactive applications.  In
-- contrast to the callback model, transient transparently moves the relevant
-- state to the respective event threads and composes the results to arrive at
-- the new state. The programmer is not aware of the threads, there is no
-- shared state to worry about, and a seamless sequential flow enabling easy
-- reasoning and composable application components.
-- <https://hackage.haskell.org/package/axiom Axiom> is a client and server
-- side web UI and reactive application framework built using the transient
-- programming model.
--
-- = Further Reading
--
-- * <https://github.com/transient-haskell/transient/wiki/Transient-tutorial Tutorial>
-- * <https://github.com/transient-haskell/transient-examples Examples>
--
-----------------------------------------------------------------------------

module Transient.Base(
-- * The Monad
TransIO, TransientIO

-- * Task Composition Operators
, (**>), (<**), (<***)

-- * Running the monad
,keep, keep', stop, exit

-- * Asynchronous console IO
,option, input,input'

-- * Task Creation
-- $taskgen
, StreamData(..)
,parallel, async, waitEvents, sample, spawn, react, abduce

-- * State management
,setData, getSData, getData, delData, modifyData, modifyData', try, setState, getState, delState, getRState,setRState, modifyState

-- * Thread management
, threads,addThreads, freeThreads, hookedThreads,oneThread, killChilds

-- * Exceptions
-- $exceptions

,onException, onException', cutExceptions, continue, catcht, throwt

-- * Utilities
,genId
)

where


import    Transient.Internals

-- $taskgen
--
-- These primitives are used to create asynchronous and concurrent tasks from
-- an IO action.
--

-- $exceptions
--
-- Exception handlers are implemented using the backtracking mechanism.
-- (see 'Transient.Backtrack.back'). Several exception handlers can be
-- installed using 'onException'; handlers are run in reverse order when an
-- exception is raised. The following example prints "3" and then "2".
--
-- @
-- {-\# LANGUAGE ScopedTypeVariables #-}
-- import Transient.Base (keep, onException, cutExceptions)
-- import Control.Monad.IO.Class (liftIO)
-- import Control.Exception (ErrorCall)
--
-- main = keep $ do
--     onException $ \\(e:: ErrorCall) -> liftIO $ putStrLn "1"
--     cutExceptions
--     onException $ \\(e:: ErrorCall) -> liftIO $ putStrLn "2"
--     onException $ \\(e:: ErrorCall) -> liftIO $ putStrLn "3"
--     liftIO $ error "Raised ErrorCall exception" >> return ()
-- @