-
Notifications
You must be signed in to change notification settings - Fork 17
Open
Description
We don't have any Bluefin-specific concurrency primitives and just rely on MonadUnliftIO to give us access to IO currency primitives. This seems dangerous, firstly in light of #29, but also because we could actually use Bluefin's type system to forbid thread-unsafe access to resources.
By way of comparison, effectful seems fairly lax. See haskell-effectful/effectful#292.
#!/usr/bin/env cabal
{- cabal:
build-depends: base, effectful==2.5.1.0, async
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
import Control.Concurrent
import Control.Concurrent.Async
import Data.IORef
import Effectful
import Effectful.Dispatch.Dynamic
import Effectful.State.Dynamic
evalState ::
(IOE :> es) =>
s ->
Eff (State s : es) a ->
Eff es a
evalState s0 m = do
v <- liftIO (newIORef s0)
reinterpret id (ioState v) m
ioState ::
(IOE :> es) =>
IORef s ->
LocalEnv localEs es ->
State s (Eff localEs) a ->
Eff es a
ioState v env = \case
Get -> liftIO (readIORef v)
Put s -> liftIO (writeIORef v s)
State f -> liftIO $ do
s <- readIORef v
let (r, s') = f s
writeIORef v s
pure r
StateM _ -> error "Dunno"
useStateConcurrently ::
(State Int :> es, IOE :> es) => Eff es ()
useStateConcurrently = do
withEffToIO (ConcUnlift Persistent Unlimited) $
\effToIO -> do
concurrently
( effToIO $ do
liftIO (threadDelay 500)
s <- get @Int
put (s + 1)
)
( effToIO $ do
s <- get @Int
liftIO (threadDelay 1000)
put (s * 2)
)
(liftIO . print) =<< get @Int
-- We "want" the result to be either
--
-- - 12 (== (5 + 1) * 2), or
--
-- - 11 (== (5 * 2) + 1)
--
-- but we get
--
-- % cabal run test-effectful-thread-unsafe.hs
-- 10
main :: IO ()
main = runEff $ do
evalState @_ @Int 5 $ do
useStateConcurrentlyMetadata
Metadata
Assignees
Labels
No labels