-
Notifications
You must be signed in to change notification settings - Fork 17
Open
Description
Hi,
To learn Bluefin and wider effect systems, I'm working on Snake will replays and leaderboards etc. Right now, I'm trying to solve multithreaded logging and wanted to try out how to do it with WriterT / StateT and Bluefin.
The WriterT code looks like this:
import Data.Text (Text)
import qualified Data.Text as Text
import Control.Monad.Writer (WriterT)
import qualified Control.Monad.Writer.Lazy as W
someProgram :: IO ()
-- >>> someProgram
someProgram = do
a <- do logActionW (pure ()) "Not adding two numbers, just messing about"
logActionW (pure (12+19)) "Can I add another two?" -- gives the result of 12 + 19
putStrLn "Oh my God I'm so excited"
putStrLn $ "The value of the equation = " <> show a
{-
ghci> someProgram
Not adding two numbers, just messing about
Can I add another two?
Oh my God I'm so excited
The value of the equation = 31
-}
-- logActionW :: Monad m => m a -> String -> WriterT [String] m a
logActionW :: IO a -> String -> IO a
logActionW act logmsg = flushStdOut $ do
a <- lift act
W.tell . unlines . pure $ logmsg
pure a
flushW :: IO.Handle -> WriterT String IO a -> IO a
flushW h writer = do
(result, written) <- W.runWriterT writer
IO.hPutStr h written
IO.hFlush h
pure result
flushStdOut :: WriterT String IO a -> IO a
flushStdOut = flushW IO.stdoutI want to do something similar to this but with Bluefin but I'm struggling to do the multiple logActionW calls part in someProgram for someProgramBF with sendToQueue and similar functions.
newtype Logger i o e = Logger (Writer o e)
type ClientLogger = Logger (TChan ClientLogItem) Text
data ClientLogItem = ClientLog {clientID :: Int, clientAddr :: SockAddr, clientMsg :: Text}
instance Show ClientLogItem where
show (ClientLog iD sockAddr msg) =
"Client ID: " <> show iD <> "| Client Addr: " <> show sockAddr <> ": " <> Text.unpack msg
sendToQueue :: (e1 :> es, e :> es) => IOE e1 -> TChan ClientLogItem -> ClientLogItem -> ClientLogger e -> Eff es ()
sendToQueue io clq cl =
logActionClientLoggerIO io
(atomically $ writeTChan clq cl)
("Writing clientID " <> Text.pack (show (clientID cl)) <> " to the queue")
-- logClient :: (e :> es) => IOE e -> TChan ClientLogItem -> ClientLogger e -> Eff es ()
-- logClient :: (e1 :> es, e :> es) => IOE e1 -> TChan ClientLogItem -> ClientLogger e -> Eff es ClientLogItem
logClient :: (e1 :> es, e :> es) => IOE e1 -> TChan ClientLogItem -> ClientLogger e -> Eff es ClientLogItem
logClient io clq l = do
cl <- logActionClientLoggerIO io (atomically $ readTChan clq) "Pulling from the client from the queue" l
logActionClientLoggerIO io (pure cl) ("Logged client: " <> Text.pack (show cl)) l
-- spawnClientLogger :: (e :> es) => (forall e. ClientLogger e -> Eff (e :& es) r) -> Eff es r
spawnClientLogger :: (e :> es) => Writer Text e -> (forall e. ClientLogger e -> Eff (e :& es) r) -> Eff es r
spawnClientLogger w k = useImplIn k $ Logger (mapHandle w)
logActionClientLoggerIO :: (e1 :> es, e :> es) => IOE e1 -> IO b -> Text -> ClientLogger e -> Eff es b
logActionClientLoggerIO io ioAct logmsg (Logger str) = do
a <- effIO io ioAct
tell str logmsg
pure a
logActionClientLogger :: (e :> es) => Eff es b -> Text -> ClientLogger e -> Eff es b
logActionClientLogger act logmsg (Logger str) = do
a <- act
tell str logmsg
pure a
-- runLoggerBF :: IO ([Text], ())
-- runLoggerBF :: (forall e. ClientLogger e -> Eff (e :& es) r) -> IO ([Text], r)
someProgramBF io = do
chan <- effIO io newTChanIO
execWriter $ \w -> spawnClientLogger w $ do
sendToQueue io chan (ClientLog undefined undefined undefined)
-- sendToQueue io chan (ClientLog undefined undefined undefined)
-- clientLogger $ sendToQueue io chan (ClientLog undefined undefined undefined)
-- clientLogger $ logActionClientLoggerIO io (putStrLn "Wow") "What is this?"
-- clientLogger $ logClient io chan
pure ()
-- logActionClientLoggerIO io (putStrLn "Wow") "What is this?"I get the feeling that the (forall e. ClientLogger e -> Eff (e :& es) r) part isn't actually a monad and so I can't do that kind of sequencing part?
The full implementation so far is here
Thanks for the help in advance :)
Metadata
Metadata
Assignees
Labels
No labels