Skip to content

Instantly share code, notes, and snippets.

@kana-sama
Last active November 6, 2021 11:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kana-sama/c96ed47501bb9f5ed0da332caebd8666 to your computer and use it in GitHub Desktop.
Save kana-sama/c96ed47501bb9f5ed0da332caebd8666 to your computer and use it in GitHub Desktop.
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecursiveDo #-}
import Control.Concurrent
import Control.Concurrent.STM
data PID msg = PID
{ pid :: ThreadId,
mailBox :: TQueue msg
}
newtype Behavior msg = Behavior ((?self :: PID msg) => msg -> IO (Behavior msg))
spawn :: forall msg. Behavior msg -> IO (PID msg)
spawn beh = mdo
mailBox <- atomically newTQueue
let lifecycle (Behavior beh) = do
msg <- atomically (readTQueue mailBox)
beh <- beh msg
lifecycle beh
pid <- forkIO do
let ?self = self
lifecycle beh
pure ()
let self = PID {pid, mailBox}
pure self
(!) :: PID msg -> msg -> IO ()
p ! msg = atomically (writeTQueue (mailBox p) msg)
data Ping = Ping {caller :: PID Pong}
data Pong = Pong {caller :: PID Ping}
mkPing :: Behavior Ping
mkPing = go 0
where
go n = Behavior \(Ping caller) -> do
putStrLn ("Ping! #" <> show n)
threadDelay 1_000_000
caller ! Pong ?self
pure (go (n + 1))
mkPong :: Behavior Pong
mkPong = go 0
where
go n = Behavior \(Pong caller) -> do
putStrLn ("Pong! #" <> show n)
threadDelay 1_000_000
caller ! Ping ?self
pure (go (n + 1))
main = do
ping <- spawn mkPing
pong <- spawn mkPong
ping ! Ping pong
threadDelay 10_000_000
-- Ping! #0
-- Pong! #0
-- Ping! #1
-- Pong! #1
-- Ping! #2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment