-- | A complete example for the library module Control.Eff.Concurrent.Examples where import GHC.Stack import Control.Eff import Control.Eff.Lift import Control.Monad import Data.Dynamic import Control.Eff.Concurrent import qualified Control.Exception as Exc data TestApi deriving Typeable data instance Api TestApi x where SayHello :: String -> Api TestApi ('Synchronous Bool) Shout :: String -> Api TestApi 'Asynchronous Terminate :: Api TestApi ('Synchronous ()) TerminateError :: String -> Api TestApi ('Synchronous ()) deriving (Typeable) data MyException = MyException deriving Show instance Exc.Exception MyException deriving instance Show (Api TestApi x) main :: IO () main = defaultMain (example forkIoScheduler) mainProcessSpawnsAChildAndReturns :: (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r () mainProcessSpawnsAChildAndReturns px = void (spawn (void (receiveMessage px))) example :: ( HasCallStack , SetMember Process (Process q) r , Member (Logs LogMessage) r , Member (Logs LogMessage) q , SetMember Lift (Lift IO) q , SetMember Lift (Lift IO) r ) => SchedulerProxy q -> Eff r () example px = do me <- self px logInfo ("I am " ++ show me) server <- asServer @TestApi <$> spawn testServerLoop logInfo ("Started server " ++ show server) let go = do x <- lift getLine case x of ('k' : rest) -> do callRegistered px (TerminateError rest) go ('s' : _) -> do callRegistered px Terminate go ('c' : _) -> do castRegistered px (Shout x) go ('r' : rest) -> do void (replicateM (read rest) (castRegistered px (Shout x))) go ('q' : _) -> logInfo "Done." _ -> do res <- ignoreProcessError px (callRegistered px (SayHello x)) logInfo ("Result: " ++ show res) go registerServer server go testServerLoop :: forall r . (HasCallStack, Member (Logs LogMessage) r, SetMember Lift (Lift IO) r) => Eff (Process r ': r) () testServerLoop = serve px $ ApiHandler handleCast handleCall handleTerminate where px :: SchedulerProxy r px = SchedulerProxy handleCast :: Api TestApi 'Asynchronous -> Eff (Process r ': r) () handleCast (Shout x) = do me <- self px logInfo (show me ++ " Shouting: " ++ x) handleCall :: Api TestApi ( 'Synchronous x) -> (x -> Eff (Process r ': r) ()) -> Eff (Process r ': r) () handleCall (SayHello "e1") _reply = do me <- self px logInfo (show me ++ " raising an error") raiseError px "No body loves me... :,(" handleCall (SayHello "e2") _reply = do me <- self px logInfo (show me ++ " throwing a MyException ") lift (Exc.throw MyException) handleCall (SayHello "self") reply = do me <- self px logInfo (show me ++ " casting to self") cast px (asServer @TestApi me) (Shout "from me") void (reply False) handleCall (SayHello "die") reply = do me <- self px logInfo (show me ++ " throwing and catching ") catchRaisedError px (\er -> logInfo ("WOW: " ++ show er ++ " - No. This is wrong!")) (raiseError px "No body loves me... :,(") void (reply True) handleCall (SayHello x) reply = do me <- self px logInfo (show me ++ " Got Hello: " ++ x) void (reply (length x > 3)) handleCall Terminate reply = do me <- self px logInfo (show me ++ " exiting") void (reply ()) exitNormally px handleCall (TerminateError msg) reply = do me <- self px logInfo (show me ++ " exiting with error: " ++ msg) void (reply ()) exitWithError px msg handleTerminate msg = do me <- self px logInfo (show me ++ " is exiting: " ++ show msg) maybe (exitNormally px) (exitWithError px) msg