SamuelSchlesinger / stm-actor

An implementation of the actor model in Haskell using STM
MIT License
16 stars 3 forks source link

Doubt about the library #8

Closed tonicebrian closed 1 year ago

tonicebrian commented 1 year ago

Hi, I'm evaluating your library to see if it will fit my use case but I cannot make it to work. Could you spot why this code doesn't work?

#!/usr/bin/env stack
-- stack --resolver lts-20.6 script --package stm-actor --package stm-queue --package stm --package lens --package transformers --package mtl

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}

import Control.Concurrent (threadDelay)
import Control.Concurrent.Actor (ActionT, act, hoistActionT, receive, send)
import Control.Concurrent.STM (atomically)
import Control.Lens (makeLenses, use, (+=))
import Control.Monad (forM)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.State.Class (MonadState)
import Control.Monad.Trans.State (evalStateT)
import System.IO (IO, print, putStrLn)
import Prelude

data Tick = Tick

newtype TickState = TickState {_counter :: Int}

makeLenses ''TickState

accountant :: (MonadState TickState m, MonadIO m) => ActionT Tick m ()
accountant = receive \msg -> do
  counter += 1
  currentSt <- use counter
  liftIO $ putStrLn ("Current counter at: " <> show currentSt)

main :: IO ()
main = do
  actor <- act (hoistActionT (\prog -> evalStateT prog (TickState 0)) accountant)
  forM_ [1 .. 5] $ \idx -> do
    atomically $ send actor Tick
  threadDelay 1_000_000
  putStrLn "This is the end"

I'd expect to see 5 logs but I can only see 1:

❯ ./actor.hs
Current counter at: 1
This is the end

Thanks!!

SamuelSchlesinger commented 1 year ago

Why would you expect to see 5 logs? My understanding of your ActionT is that it receives a single message, increments a counter once, and then prints the current counter. If you want to loop and receive more, you'll have to do that explicitly. By adding a call to accountant at the end of accountant, I see:

*MyLib> main
Current counter at: 1
Current counter at: 2
Current counter at: 3
Current counter at: 4
Current counter at: 5
This is the end
SamuelSchlesinger commented 1 year ago

I'll close this issue soon, let me know if you are satisfied with my response. Thanks for reminding me to update this package for modern GHCs, also!

tonicebrian commented 1 year ago

Ohh, thank you, reminder to self: don't work late in the evening!!

SamuelSchlesinger commented 1 year ago

As evidenced by my being up, sometimes its inevitable! What was your possible use case for stm-actor, by the way?

tonicebrian commented 1 year ago

I'm creating a game server for boardgames. There will be an actor holding the state of each game, game clients will connect using web sockets and they will modify the state through messages to the actor.

At first I thought about a ReaderT solution and manage the queue myself, but then I realized that there are two kind of states, the state for the match (which clients are connected and should receive updates) and the state of the game (only the game state itself, and 2 mailboxes to send commands to players).

Each has different concurrency requirements. For instance you cannot block the Match Actor waiting for a client to be available in order to send a move request because maybe you have enqueued a message to connect that missing client. So I realized that I was creating an actor system and looked around and found your actor framework.

SamuelSchlesinger commented 1 year ago

Sounds fun! You may have better luck latency-wise going with unagi-chan rather than the underlying stm-queue library that backs this package, but my guess is that for most board games you should probably be fine with this library's performance as well.

SamuelSchlesinger commented 1 year ago

By the way, I realize that my README documentation sort of conveyed that the example you gave should do what you expected. I just made a commit to hopefully clarify that you need to write a loop to continually log.

tonicebrian commented 1 year ago

Yep, the README is clearer now. Thanks a lot for the library.