ReaderT Design Pattern Reflection

:set +m :set -package stm :set -package transforms :set -package lifted-async :set -package mtl
{-# LANGUAGE FlexibleContexts #-} import Control.Concurrent.Async.Lifted.Safe import Control.Monad.Reader import Control.Concurrent.STM modify :: (MonadReader (TVar Int) m, MonadIO m) => (Int -> Int) -> m () modify f = do ref <- ask liftIO $ atomically $ modifyTVar' ref f ref <- newTVarIO 4 runReaderT (concurrently (modify (+ 1)) (modify (+ 2))) ref readTVarIO ref >>= print
4

org mode の source block では 4 になってしまう。正しくは 7

cabal ではうまくいく。

#!/usr/bin/env cabal {- cabal: build-depends: base, stm, lifted-async, transformers, mtl -} {-# LANGUAGE FlexibleContexts #-} import Control.Concurrent.Async.Lifted.Safe import Control.Monad.Reader import Control.Concurrent.STM modify :: (MonadReader (TVar Int) m, MonadIO m) => (Int -> Int) -> m () modify f = do ref <- ask liftIO $ atomically $ modifyTVar' ref f main :: IO () main = do ref <- newTVarIO 4 runReaderT (concurrently (modify (+ 1)) (modify (+ 2))) ref readTVarIO ref >>= print
7

応用として、 m() ではなく、 m(Maybe Int) とするとこんな風になる。

#!/usr/bin/env cabal {- cabal: build-depends: base, stm, lifted-async, transformers, mtl -} {-# LANGUAGE FlexibleContexts #-} import Control.Concurrent.Async.Lifted.Safe import Control.Monad.Reader import Control.Concurrent.STM modify :: (MonadReader (TVar Int) m, MonadIO m) => (Int -> Int) -> m (Maybe Int) modify f = do ref <- ask liftIO $ atomically $ do modifyTVar' ref f Just <$> readTVar ref main :: IO () main = do ref <- newTVarIO 4 res <- runReaderT (concurrently (modify (+ 1)) (modify (+ 2))) ref readTVarIO ref >>= print print res
(Just 5,Just 7)

concurrently の type signature は

concurrently :: forall m a b. (MonadBaseControl IO m, Forall (Pure m)) => m a -> m b -> m (a, b)

なので、結果は tuple でよい。

Reference

https://www.fpcomplete.com/blog/readert-design-pattern/