SlideShare a Scribd company logo
Concurrent applications
with Free monads and STM
Haskell Love 2020
1
Alexander Granin
graninas@gmail.com
Twitter: @graninas
Plan
● In love with Free monads and STM
● Testing?
● How does this magic work?
● Performance?
● Conclusion: The truths I learned
● (Bonus) No, really, how does this magic work?
2
In Love with Free monads and STM
3
4
Labyrinth game (Hydra framework)
5
printLabyrinth :: AppState -> LangL ()
printLabyrinth state = do
lab <- readVarIO (state ^. labyrinth)
plPos <- readVarIO (state ^. playerPos)
let labRender = renderLabyrinth lab plPos
printLabyrinthRender labRender
data AppState = AppState
{ _labyrinth :: StateVar Labyrinth
, _playerPos :: StateVar PlayerPos
, _gameState :: StateVar GameState
}
Labyrinth game
6
printLabyrinth :: AppState -> LangL ()
printLabyrinth state = do
lab <- readVarIO (state ^. labyrinth)
plPos <- readVarIO (state ^. playerPos)
let labRender = renderLabyrinth lab plPos
printLabyrinthRender labRender
data AppState = AppState
{ _labyrinth :: StateVar Labyrinth
, _playerPos :: StateVar PlayerPos
, _gameState :: StateVar GameState
}
Labyrinth game
Free monadic
scenario
7
printLabyrinth :: AppState -> LangL ()
printLabyrinth state = do
lab <- readVarIO (state ^. labyrinth)
plPos <- readVarIO (state ^. playerPos)
let labRender = renderLabyrinth lab plPos
printLabyrinthRender labRender
data AppState = AppState
{ _labyrinth :: StateVar Labyrinth
, _playerPos :: StateVar PlayerPos
, _gameState :: StateVar GameState
}
-- | Concurrent variable
newtype StateVar a = StateVar
{ _varId :: Int
}
Labyrinth game
8
printLabyrinth :: AppState -> LangL ()
printLabyrinth state = do
lab <- readVarIO (state ^. labyrinth)
plPos <- readVarIO (state ^. playerPos)
let labRender = renderLabyrinth lab plPos
printLabyrinthRender labRender
data AppState = AppState
{ _labyrinth :: StateVar Labyrinth
, _playerPos :: StateVar PlayerPos
, _gameState :: StateVar GameState
}
-- | Concurrent variable
newtype StateVar a = StateVar
{ _varId :: Int
}
Labyrinth game
Magic!
(Typed Avatar pattern)
9
Labyrinth game
labyrinthApp :: AppState -> AppL ()
labyrinthApp st = do
scenario $ putStrLn "Labyrinth (aka Terra Incognita) game"
cliToken <- cli (onStep st) (onUnknownCommand st) $ do
cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp
cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown
cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft
cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight
cmd "quit" $ quit st
10
Labyrinth game
labyrinthApp :: AppState -> AppL ()
labyrinthApp st = do
scenario $ putStrLn "Labyrinth (aka Terra Incognita) game"
cliToken <- cli (onStep st) (onUnknownCommand st) $ do
cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp
cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown
cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft
cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight
cmd "quit" $ quit st
Control Structure pattern
11
Labyrinth game
labyrinthApp :: AppState -> AppL ()
labyrinthApp st = do
scenario $ putStrLn "Labyrinth (aka Terra Incognita) game"
cliToken <- cli (onStep st) (onUnknownCommand st) $ do
cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp
cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown
cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft
cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight
cmd "quit" $ quit st
atomically $ do
finished <- readVar $ cliFinishedToken cliToken
when (not finished) retry
Free monadic eDSL over STM
Control Structure pattern
12
MeteorCounter app (Hydra framework)
13
MeteorCounter app (Hydra framework)
meteorsMonitoring :: AppConfig -> AppL ()
meteorsMonitoring cfg = do
st <- atomically $ initState cfg
process $ forever $ meteorCounter st
process $ forever $ withRandomDelay st $ meteorShower st NorthEast
process $ forever $ withRandomDelay st $ meteorShower st NorthWest
process $ forever $ withRandomDelay st $ meteorShower st SouthEast
process $ forever $ withRandomDelay st $ meteorShower st SouthWest
atomically $ do
let totalVar :: StateVar Int = _totalMeteors st
total <- readVar totalVar
when (total < 1000) retry
14
MeteorCounter app (Hydra framework)
meteorsMonitoring :: AppConfig -> AppL ()
meteorsMonitoring cfg = do
st <- atomically $ initState cfg
process $ forever $ meteorCounter st
process $ forever $ withRandomDelay st $ meteorShower st NorthEast
process $ forever $ withRandomDelay st $ meteorShower st NorthWest
process $ forever $ withRandomDelay st $ meteorShower st SouthEast
process $ forever $ withRandomDelay st $ meteorShower st SouthWest
atomically $ do
let totalVar :: StateVar Int = _totalMeteors st
total <- readVar totalVar
when (total < 1000) retry
Processes
15
MeteorCounter app (Hydra framework)
meteorsMonitoring :: AppConfig -> AppL ()
meteorsMonitoring cfg = do
st <- atomically $ initState cfg
process $ forever $ meteorCounter st
process $ forever $ withRandomDelay st $ meteorShower st NorthEast
process $ forever $ withRandomDelay st $ meteorShower st NorthWest
process $ forever $ withRandomDelay st $ meteorShower st SouthEast
process $ forever $ withRandomDelay st $ meteorShower st SouthWest
atomically $ do
let totalVar :: StateVar Int = _totalMeteors st
total <- readVar totalVar
when (total < 1000) retry
Finish condition
16
Blockchain app (Node framework)
Graph Node
Graph Node
PoW Node
TCP
UDP
JSON RPC
17
Blockchain app
graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL ()
graphNode cfg nodeData = do
let gsData = nodeData ^. graphServiceData
serving Udp (cfg ^. nodeUdpPort) $ do
handler $ methodPing
handler $ acceptKBlock gsData
process $ forever $ do
awaitSignal $ gsData ^. dumpToDBSignal
dumpToDB gsData
process $ forever $ do
awaitSignal $ gsData ^. restoreFromDBSignal
restoreFromDB gsData
std $ do
stdHandler $ stopNodeHandler nodeData
awaitNodeFinished nodeData
18
Blockchain app
graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL ()
graphNode cfg nodeData = do
let gsData = nodeData ^. graphServiceData
serving Udp (cfg ^. nodeUdpPort) $ do
handler $ methodPing
handler $ acceptKBlock gsData
process $ forever $ do
awaitSignal $ gsData ^. dumpToDBSignal
dumpToDB gsData
process $ forever $ do
awaitSignal $ gsData ^. restoreFromDBSignal
restoreFromDB gsData
std $ do
stdHandler $ stopNodeHandler nodeData
awaitNodeFinished nodeData
UDP Service
(Declarative
Protocol pattern)
19
Blockchain app
graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL ()
graphNode cfg nodeData = do
let gsData = nodeData ^. graphServiceData
serving Udp (cfg ^. nodeUdpPort) $ do
handler $ methodPing
handler $ acceptKBlock gsData
process $ forever $ do
awaitSignal $ gsData ^. dumpToDBSignal
dumpToDB gsData
process $ forever $ do
awaitSignal $ gsData ^. restoreFromDBSignal
restoreFromDB gsData
std $ do
stdHandler $ stopNodeHandler nodeData
awaitNodeFinished nodeData
Background
dump / restore
processes
20
Blockchain app
graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL ()
graphNode cfg nodeData = do
let gsData = nodeData ^. graphServiceData
serving Udp (cfg ^. nodeUdpPort) $ do
handler $ methodPing
handler $ acceptKBlock gsData
process $ forever $ do
awaitSignal $ gsData ^. dumpToDBSignal
dumpToDB gsData
process $ forever $ do
awaitSignal $ gsData ^. restoreFromDBSignal
restoreFromDB gsData
std $ do
stdHandler $ stopNodeHandler nodeData
awaitNodeFinished nodeData
CLI
& Node finish condition
21
Blockchain app state
data GraphNodeData = GraphNodeData
{ _graphServiceData :: GraphServiceData
, _status :: StateVar NodeStatus
}
data GraphServiceData = GraphServiceData
{ _blockchain :: BlockchainData
, _db :: Maybe DBModel
, _dumpToDBSignal :: StateVar Bool
, _restoreFromDBSignal :: StateVar Bool
, _checkPendingSignal :: StateVar Bool
}
Node
State
Node
Configs
Scenarios (Free monad chains)
Process Process
Graph
Process
STM transactions
22
Blockchain app state
data GraphNodeData = GraphNodeData
{ _graphServiceData :: GraphServiceData
, _status :: StateVar NodeStatus
}
data GraphServiceData = GraphServiceData
{ _blockchain :: BlockchainData
, _db :: Maybe DBModel
, _dumpToDBSignal :: StateVar Bool
, _restoreFromDBSignal :: StateVar Bool
, _checkPendingSignal :: StateVar Bool
}
awaitSignal :: (Monad m, StateIO m) => StateVar Bool -> m ()
awaitSignal signalVar = do
atomically $ unlessM (readVar signalVar) retry
writeVarIO signalVar False
Signal vars
23
Concurrent STM-based graph
Active window
Request
Request
Request
KV DB
STM-based transactions
24
addMBlock :: WindowedGraph -> Microblock -> StateL Bool
addMBlock wndGraph mblock@(Microblock hash _ _ _) = do
kblock <- getKBlock wndGraph hash
unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")."
when (isJust kblock) $ do
logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")."
evalGraph wndGraph $ do
newNode (MBlockContent mblock)
newLink hash (MBlockContent mblock)
pure $ isJust kblock
Graph code sample
25
addMBlock :: WindowedGraph -> Microblock -> StateL Bool
addMBlock wndGraph mblock@(Microblock hash _ _ _) = do
kblock <- getKBlock wndGraph hash
unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")."
when (isJust kblock) $ do
logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")."
evalGraph wndGraph $ do
newNode (MBlockContent mblock)
newLink hash (MBlockContent mblock)
pure $ isJust kblock
Graph code sample
STM-like transaction eDSL
newVar
readVar
writeVar
retry
+Logger interface
26
addMBlock :: WindowedGraph -> Microblock -> StateL Bool
addMBlock wndGraph mblock@(Microblock hash _ _ _) = do
kblock <- getKBlock wndGraph hash
unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")."
when (isJust kblock) $ do
logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")."
evalGraph wndGraph $ do
newNode (MBlockContent mblock)
newLink hash (MBlockContent mblock)
pure $ isJust kblock
Graph code sample
Work with graph
NewNode
DeleteNode
NewLink
DeleteLink
GetNode
ClearGraph
27
addMBlock :: WindowedGraph -> Microblock -> StateL Bool
addMBlock wndGraph mblock@(Microblock hash _ _ _) = do
kblock <- getKBlock wndGraph hash
unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")."
when (isJust kblock) $ do
logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")."
evalGraph wndGraph $ do
newNode (MBlockContent mblock)
newLink hash (MBlockContent mblock)
pure $ isJust kblock
Graph code sample
Logging within the transaction
Testing?
28
♡
29
spec :: Spec
spec = unstableTest $ slowTest
$ describe "PoW and graph node interaction"
$ fromHUnitTest $ TestList
[ TestLabel "Accept kblocks produced in order" $ testAcceptKblock InOrder
, TestLabel "Accept kblocks produced in random order" $ testAcceptKblock RandomOrder
]
testAcceptKblock :: Ordering -> Test
testAcceptKblock order = TestCase $ withNodesManager $ mgr -> do
void $ startNode mgr $ graphNode graphNodeTransmitterConfig
waitForNode transmitterRpcAddress
void $ startNode mgr $ powNode $ genPoWNodeConfig { _kblocksOrder = order}
waitForNode powRpcAddress
void $ makeIORpcRequest powRpcAddress $ NBlockPacketGeneration kblockCount timeGap
let predicate kBlock = kBlock ^. number == kblockCount
void $ makeRpcRequestWithPredicate predicate transmitterRpcAddress GetLastKBlock
Testing nodes (virtual environment)
30
spec :: Spec
spec = do
around (withCoreRuntime Nothing) // Arrange
$ it "generated labyrinth has correct bounds"
$ runtime -> property
$ withMaxSuccess 5
$ monadicIO
$ do
eLab <- run $ try $ runLangL runtime generateRndLabyrinth // Act
case eLab of
Left (err :: SomeException) -> assert False // Assert
Right lab -> do
let LabyrinthInfo {liBounds, liWormholes} = analyzeLabyrinth lab
let (x, y) = liBounds
let wms = Map.size liWormholes
assert $ x * y >= 16 && x * y <= 100
assert $ (wms >= 2) && (wms <= 5)
Testing the labyrinth logic (black box, property-based)
31
spec :: Spec
spec = do
around (withAppRuntime Nothing) $ // Arrange
describe "Labyrinth generation tests" $
it "generateLabyrinth" $ rt -> do
lab <- runLangL (_coreRuntime rt) $ generateLabyrinth (4, 4) 3 5 // Act
let LabyrinthInfo {liBounds, liWormholes, liExits} = analyzeLabyrinth lab
liBounds `shouldBe` (4, 4) // Assert
(Map.size liWormholes) `shouldSatisfy` (x -> x >= 2 && x <= 5)
(Set.size liExits) `shouldSatisfy` (x -> x >= 1 && x <= 3)
Testing the labyrinth logic (black box, integration)
How does this magic work?
32
It works nicely.
33
It works nicely.
34
Business logic code is very simple.
It works nicely.
35
Business logic code is very simple.
Testing is very simple.
It works nicely.
36
Business logic code is very simple.
Testing is very simple.
Complete separation of concerns.
Performance?
37
38
Performance of Free monads (dumb testing approach)
Ops cnt FT FreeM ChurchM IO
10 0.265 0.222 0.223 0.227
100 0.221 0.226 0.228 0.222
1000 0.227 0.245 0.223 0.226
10000 0.229 4.106 0.227 0.224
100000 0.289 inf 0.31 0.309
1000000 0.859 inf 1.134 0.857
10000000 6.384 inf 9.507 6.413
20000000 13.734 inf 18.997 12.588
30000000 18.16 inf 28.568 17.76
flow :: IORef Int -> AppL ()
flow ref = scenario $ do
val' <- evalIO $ readIORef ref
val <- getRandomInt (1, 100)
evalIO $ writeIORef ref $ val' + val
scenario :: Int -> AppRuntime -> IO ()
scenario ops appRt = do
ref <- newIORef 0
void $ startApp appRt (replicateM_ ops $ flow ref)
val <- readIORef ref
print val
$ time PerfTestApp2
https://github.com/graninas/Hydra/tree/master/app/PerfTestApp2
The truths I learned
PerformanceGood Design >
Performance
Perfection
Good Design
Getting Things Done
>
>
Performance
Perfection
Correctness
Good Design
Getting Things Done
Tests
>
>
>
Performance
Perfection
Correctness
Math Beauty
Good Design
Getting Things Done
Tests
Simplicity
>
>
>
>
Performance
Perfection
Correctness
Math Beauty
Technologies
Good Design
Getting Things Done
Tests
Simplicity
People
>
>
>
>
>
Performance
Perfection
Correctness
Math Beauty
Technologies
Belief
Good Design
Getting Things Done
Tests
Simplicity
People
Experiment
>
>
>
>
>
>
46
GitHub List: Software Design in Haskell
https://github.com/graninas/software-design-in-haskell👉
Hydra: framework for backend & console apps
https://github.com/graninas/Hydra👉
Node: framework for distributed apps & blockchains
https://github.com/graninas/Node👉
graninas@gmail.com
graninas
graninas_channel
StrangeMooder
granin.alexander
Alexander Granin
47
Free monads STM
http://leanpub.com/functional-design-and-archit
ecture/c/4vpQNPcmRfo1
66% discount ($60 $20)
(expires 2020-08-05)
48
Additional Materials
● Automatic White-Box Testing with Free Monads | Article, Showcase
● Hierarchical Free Monads and Software Design in Haskell | Talk
● Hierarchical Free Monads: The Most Developed Approach In Haskell
● Functional Design and Architecture | Book
● Hydra | Framework (web services with SQL/KV DB and concurrency)
● Node | Framework (distributed apps with KV DB and concurrency)
● Final Tagless vs Free Monads | Talk
● Software Design in Haskell | List of materials
No, really, how does this magic work?
49
50
Hydra Framework
Implementation & Runtime
Interfaces
(Hierarchical Free Monad eDSLs)
Domain & Business Logic
ProcessL
Runtime, Interpreters, Configs, Environment
Application
Domain
Model
Business
Logic
DB Model
AppL
SqlDBL
LangL
Beam
LoggerL
StateL
51
newtype StateVar a = StateVar { _varId :: Int }
data StateF next where
NewVar :: a -> (StateVar a -> next) -> StateF next
ReadVar :: StateVar a -> (a -> next) -> StateF next
WriteVar :: StateVar a -> a -> (() -> next) -> StateF next
Retry :: (a -> next) -> StateF next
EvalGraph :: TGraph c -> Free (HGraphF (TNodeL c)) x -> (x -> next) -> StateF next
EvalDelayedLogger :: LoggerL () -> (() -> next) -> StateF next
type StateL = Free StateF
STM-like Free interface
52
STM-like Free language -> STM
newVar' :: StateRuntime -> a -> STM VarId
newVar' stateRt !a = do
nodeState <- takeTMVar $ stateRt ^. state
varId <- getVarId stateRt
tvar <- newTVar $ unsafeCoerce a
let !newMap = Map.insert varId (VarHandle tvar) nodeState
putTMVar (stateRt ^. state) newMap
pure varId
interpretStateF :: StateRuntime -> StateF a -> STM a
interpretStateF _ (Retry _) = retry
interpretStateF stateRt (NewVar !val next) = do
var <- newVar' stateRt val
pure $ next $ StateVar var
runStateL :: StateRuntime -> StateL a -> STM a
runStateL stateRt = foldFree (interpretStateF stateRt)
53
Container language
data LangF next where
EvalLogger :: LoggerL () -> (() -> next) -> LangF next
EvalIO :: IO a -> (a -> next) -> LangF next
...
EvalStateAtomically :: StateL a -> (a -> next) -> LangF next
type LangL = Free LangF
atomically :: StateL a -> LangL a
atomically action = liftF $ EvalStateAtomically action id
54
Upper level language -> IO
interpretLangF :: CoreRuntime -> LangF a -> IO a
interpretLangF coreRt (EvalStateAtomically action next) = do
let stateRt = coreRt ^. stateRuntime
let logHndl = coreRt ^. loggerRuntime . hsLoggerHandle
res <- atomically $ runStateL stateRt action
flushStmLogger (stateRt ^. stmLog) logHndl
pure $ next res
interpretLangF _ (EvalIO f next) = do
!r <- f
pure $ next r
interpretLangF coreRt (EvalLogger loggerAct next) =
next <$> runLoggerL (coreRt ^. loggerRuntime . hsLoggerHandle) loggerAct
55
Behind the scenes...
newtype VarHandle = VarHandle (TVar Any)
data StateRuntime = StateRuntime
{ _varId :: TVar VarId -- ^ Var id counter
, _state :: TMVar (Map VarId VarHandle) -- ^ Tracked variables
, _stmLog :: TVar Log -- ^ Stm log entries
}
data CoreRuntime = CoreRuntime
{ _stateRuntime :: StateRuntime
, _rocksDBs :: RocksDBHandles
, _redisConns :: RedisConnections
, _loggerRuntime :: LoggerRuntime
, _processRuntime :: ProcessRuntime
, _sqlConns :: MVar (Map ConnTag NativeSqlConn)
, _httpClientManager :: Manager
, _cmdVerbosity :: CmdVerbosity
}

More Related Content

What's hot

React. Redux. Real world.
React. Redux. Real world.React. Redux. Real world.
React. Redux. Real world.
Rost Galkin
 
Quantum neural network
Quantum neural networkQuantum neural network
Quantum neural network
Vijayananda Mohire
 
Меняем javascript с помощью javascript
Меняем javascript с помощью javascriptМеняем javascript с помощью javascript
Меняем javascript с помощью javascript
Pavel Volokitin
 
The Ring programming language version 1.5.1 book - Part 65 of 180
The Ring programming language version 1.5.1 book - Part 65 of 180The Ring programming language version 1.5.1 book - Part 65 of 180
The Ring programming language version 1.5.1 book - Part 65 of 180
Mahmoud Samir Fayed
 
What is row level isolation on cassandra
What is row level isolation on cassandraWhat is row level isolation on cassandra
What is row level isolation on cassandraKazutaka Tomita
 
ZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 VersionZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 Version
Ian Barber
 
Understanding the nodejs event loop
Understanding the nodejs event loopUnderstanding the nodejs event loop
Understanding the nodejs event loop
Saurabh Kumar
 
Reactive Programming with RxSwift
Reactive Programming with RxSwiftReactive Programming with RxSwift
Reactive Programming with RxSwift
Scott Gardner
 
Reactive programming with RxSwift
Reactive programming with RxSwiftReactive programming with RxSwift
Reactive programming with RxSwift
Scott Gardner
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
名辰 洪
 
Assignment no39
Assignment no39Assignment no39
Assignment no39Jay Patel
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
Ian Barber
 
Zone.js 2017
Zone.js 2017Zone.js 2017
Zone.js 2017
Jia Li
 
Travel management
Travel managementTravel management
Travel management1Parimal2
 
Bangun datar dan bangun ruang
Bangun datar dan bangun ruangBangun datar dan bangun ruang
Bangun datar dan bangun ruang
SanSan Yagyoo
 
Modern c++ Memory Management
Modern c++ Memory ManagementModern c++ Memory Management
Modern c++ Memory Management
Alan Uthoff
 
The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189
Mahmoud Samir Fayed
 
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
Shift Conference
 
Mysql handle socket
Mysql handle socketMysql handle socket
Mysql handle socket
Philip Zhong
 
Mysql5.1 character set testing
Mysql5.1 character set testingMysql5.1 character set testing
Mysql5.1 character set testing
Philip Zhong
 

What's hot (20)

React. Redux. Real world.
React. Redux. Real world.React. Redux. Real world.
React. Redux. Real world.
 
Quantum neural network
Quantum neural networkQuantum neural network
Quantum neural network
 
Меняем javascript с помощью javascript
Меняем javascript с помощью javascriptМеняем javascript с помощью javascript
Меняем javascript с помощью javascript
 
The Ring programming language version 1.5.1 book - Part 65 of 180
The Ring programming language version 1.5.1 book - Part 65 of 180The Ring programming language version 1.5.1 book - Part 65 of 180
The Ring programming language version 1.5.1 book - Part 65 of 180
 
What is row level isolation on cassandra
What is row level isolation on cassandraWhat is row level isolation on cassandra
What is row level isolation on cassandra
 
ZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 VersionZeroMQ Is The Answer: DPC 11 Version
ZeroMQ Is The Answer: DPC 11 Version
 
Understanding the nodejs event loop
Understanding the nodejs event loopUnderstanding the nodejs event loop
Understanding the nodejs event loop
 
Reactive Programming with RxSwift
Reactive Programming with RxSwiftReactive Programming with RxSwift
Reactive Programming with RxSwift
 
Reactive programming with RxSwift
Reactive programming with RxSwiftReactive programming with RxSwift
Reactive programming with RxSwift
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
 
Assignment no39
Assignment no39Assignment no39
Assignment no39
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
 
Zone.js 2017
Zone.js 2017Zone.js 2017
Zone.js 2017
 
Travel management
Travel managementTravel management
Travel management
 
Bangun datar dan bangun ruang
Bangun datar dan bangun ruangBangun datar dan bangun ruang
Bangun datar dan bangun ruang
 
Modern c++ Memory Management
Modern c++ Memory ManagementModern c++ Memory Management
Modern c++ Memory Management
 
The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189
 
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
Shift Remote FRONTEND: Reactivity in Vue.JS 3 - Marko Boskovic (Barrage)
 
Mysql handle socket
Mysql handle socketMysql handle socket
Mysql handle socket
 
Mysql5.1 character set testing
Mysql5.1 character set testingMysql5.1 character set testing
Mysql5.1 character set testing
 

Similar to Concurrent applications with free monads and stm

Final tagless vs free monad
Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monad
Alexander Granin
 
The Ring programming language version 1.5.4 book - Part 59 of 185
The Ring programming language version 1.5.4 book - Part 59 of 185The Ring programming language version 1.5.4 book - Part 59 of 185
The Ring programming language version 1.5.4 book - Part 59 of 185
Mahmoud Samir Fayed
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
Alexander Granin
 
lldb – Debugger auf Abwegen
lldb – Debugger auf Abwegenlldb – Debugger auf Abwegen
lldb – Debugger auf Abwegen
inovex GmbH
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2goMoriyoshi Koizumi
 
Scala to assembly
Scala to assemblyScala to assembly
Scala to assembly
Jarek Ratajski
 
The Ring programming language version 1.10 book - Part 69 of 212
The Ring programming language version 1.10 book - Part 69 of 212The Ring programming language version 1.10 book - Part 69 of 212
The Ring programming language version 1.10 book - Part 69 of 212
Mahmoud Samir Fayed
 
Endless fun with Arduino and Eventmachine
Endless fun with Arduino and EventmachineEndless fun with Arduino and Eventmachine
Endless fun with Arduino and Eventmachine
Bodo Tasche
 
"Coffee Script" in Brief
"Coffee Script" in Brief"Coffee Script" in Brief
"Coffee Script" in Brief
Nat Weerawan
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
The Ring programming language version 1.5.1 book - Part 8 of 180
The Ring programming language version 1.5.1 book - Part 8 of 180The Ring programming language version 1.5.1 book - Part 8 of 180
The Ring programming language version 1.5.1 book - Part 8 of 180
Mahmoud Samir Fayed
 
Lampiran b (coding)
Lampiran b (coding)Lampiran b (coding)
Lampiran b (coding)
Irsan Widyawan
 
05-Debug.pdf
05-Debug.pdf05-Debug.pdf
05-Debug.pdf
KalaiselviDevaraj
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in Golang
Dan Tran
 
The Ring programming language version 1.5.3 book - Part 9 of 184
The Ring programming language version 1.5.3 book - Part 9 of 184The Ring programming language version 1.5.3 book - Part 9 of 184
The Ring programming language version 1.5.3 book - Part 9 of 184
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.4 book - Part 9 of 185
The Ring programming language version 1.5.4 book - Part 9 of 185The Ring programming language version 1.5.4 book - Part 9 of 185
The Ring programming language version 1.5.4 book - Part 9 of 185
Mahmoud Samir Fayed
 
building_games_with_ruby_rubyconf
building_games_with_ruby_rubyconfbuilding_games_with_ruby_rubyconf
building_games_with_ruby_rubyconftutorialsruby
 
building_games_with_ruby_rubyconf
building_games_with_ruby_rubyconfbuilding_games_with_ruby_rubyconf
building_games_with_ruby_rubyconftutorialsruby
 
Encoder + decoder
Encoder + decoderEncoder + decoder
Encoder + decoder
COMSATS Abbottabad
 

Similar to Concurrent applications with free monads and stm (20)

Final tagless vs free monad
Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monad
 
The Ring programming language version 1.5.4 book - Part 59 of 185
The Ring programming language version 1.5.4 book - Part 59 of 185The Ring programming language version 1.5.4 book - Part 59 of 185
The Ring programming language version 1.5.4 book - Part 59 of 185
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
 
lldb – Debugger auf Abwegen
lldb – Debugger auf Abwegenlldb – Debugger auf Abwegen
lldb – Debugger auf Abwegen
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2go
 
Scala to assembly
Scala to assemblyScala to assembly
Scala to assembly
 
The Ring programming language version 1.10 book - Part 69 of 212
The Ring programming language version 1.10 book - Part 69 of 212The Ring programming language version 1.10 book - Part 69 of 212
The Ring programming language version 1.10 book - Part 69 of 212
 
Endless fun with Arduino and Eventmachine
Endless fun with Arduino and EventmachineEndless fun with Arduino and Eventmachine
Endless fun with Arduino and Eventmachine
 
"Coffee Script" in Brief
"Coffee Script" in Brief"Coffee Script" in Brief
"Coffee Script" in Brief
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
The Ring programming language version 1.5.1 book - Part 8 of 180
The Ring programming language version 1.5.1 book - Part 8 of 180The Ring programming language version 1.5.1 book - Part 8 of 180
The Ring programming language version 1.5.1 book - Part 8 of 180
 
Lampiran b (coding)
Lampiran b (coding)Lampiran b (coding)
Lampiran b (coding)
 
05-Debug.pdf
05-Debug.pdf05-Debug.pdf
05-Debug.pdf
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in Golang
 
The Ring programming language version 1.5.3 book - Part 9 of 184
The Ring programming language version 1.5.3 book - Part 9 of 184The Ring programming language version 1.5.3 book - Part 9 of 184
The Ring programming language version 1.5.3 book - Part 9 of 184
 
The Ring programming language version 1.5.4 book - Part 9 of 185
The Ring programming language version 1.5.4 book - Part 9 of 185The Ring programming language version 1.5.4 book - Part 9 of 185
The Ring programming language version 1.5.4 book - Part 9 of 185
 
building_games_with_ruby_rubyconf
building_games_with_ruby_rubyconfbuilding_games_with_ruby_rubyconf
building_games_with_ruby_rubyconf
 
building_games_with_ruby_rubyconf
building_games_with_ruby_rubyconfbuilding_games_with_ruby_rubyconf
building_games_with_ruby_rubyconf
 
Encoder + decoder
Encoder + decoderEncoder + decoder
Encoder + decoder
 

More from Alexander Granin

Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
Alexander Granin
 
Monadic parsers in C++
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
Alexander Granin
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
Alexander Granin
 
О разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop development
Alexander Granin
 
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Alexander Granin
 
Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...
Alexander Granin
 
Закон Деметры / Demetra's law
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
Alexander Granin
 
Design of big applications in FP
Design of big applications in FPDesign of big applications in FP
Design of big applications in FP
Alexander Granin
 
GitHub - зеркало разработчика
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчика
Alexander Granin
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
Alexander Granin
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
Alexander Granin
 
Software transactional memory. pure functional approach
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approach
Alexander Granin
 
Вы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FP
Alexander Granin
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
Alexander Granin
 
Functional microscope - Lenses in C++
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++
Alexander Granin
 
Дизайн больших приложений в ФП
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
Alexander Granin
 
Линзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция данными
Alexander Granin
 
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Alexander Granin
 
Идиоматичный функциональный код
Идиоматичный функциональный кодИдиоматичный функциональный код
Идиоматичный функциональный код
Alexander Granin
 
Функционально декларативный дизайн на C++
Функционально декларативный дизайн на C++Функционально декларативный дизайн на C++
Функционально декларативный дизайн на C++
Alexander Granin
 

More from Alexander Granin (20)

Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
 
Monadic parsers in C++
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
 
О разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop development
 
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...
 
Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...
 
Закон Деметры / Demetra's law
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
 
Design of big applications in FP
Design of big applications in FPDesign of big applications in FP
Design of big applications in FP
 
GitHub - зеркало разработчика
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчика
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
 
Software transactional memory. pure functional approach
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approach
 
Вы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FP
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
 
Functional microscope - Lenses in C++
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++
 
Дизайн больших приложений в ФП
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
 
Линзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция данными
 
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
 
Идиоматичный функциональный код
Идиоматичный функциональный кодИдиоматичный функциональный код
Идиоматичный функциональный код
 
Функционально декларативный дизайн на C++
Функционально декларативный дизайн на C++Функционально декларативный дизайн на C++
Функционально декларативный дизайн на C++
 

Recently uploaded

International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
Sebastiano Panichella
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Dutch Power
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Dutch Power
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
eCommerce Institute
 
Gregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics PresentationGregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics Presentation
gharris9
 
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
SkillCertProExams
 
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Sebastiano Panichella
 
Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
faizulhassanfaiz1670
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Sebastiano Panichella
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AwangAniqkmals
 
ASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdfASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdf
ToshihiroIto4
 
2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf
Frederic Leger
 
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
kkirkland2
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
khadija278284
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
amekonnen
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
gharris9
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Access Innovations, Inc.
 
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie WellsCollapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Rosie Wells
 

Recently uploaded (19)

International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
 
Gregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics PresentationGregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics Presentation
 
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
 
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
 
Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
 
ASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdfASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdf
 
2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf
 
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
 
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie WellsCollapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
 

Concurrent applications with free monads and stm

  • 1. Concurrent applications with Free monads and STM Haskell Love 2020 1 Alexander Granin graninas@gmail.com Twitter: @graninas
  • 2. Plan ● In love with Free monads and STM ● Testing? ● How does this magic work? ● Performance? ● Conclusion: The truths I learned ● (Bonus) No, really, how does this magic work? 2
  • 3. In Love with Free monads and STM 3
  • 5. 5 printLabyrinth :: AppState -> LangL () printLabyrinth state = do lab <- readVarIO (state ^. labyrinth) plPos <- readVarIO (state ^. playerPos) let labRender = renderLabyrinth lab plPos printLabyrinthRender labRender data AppState = AppState { _labyrinth :: StateVar Labyrinth , _playerPos :: StateVar PlayerPos , _gameState :: StateVar GameState } Labyrinth game
  • 6. 6 printLabyrinth :: AppState -> LangL () printLabyrinth state = do lab <- readVarIO (state ^. labyrinth) plPos <- readVarIO (state ^. playerPos) let labRender = renderLabyrinth lab plPos printLabyrinthRender labRender data AppState = AppState { _labyrinth :: StateVar Labyrinth , _playerPos :: StateVar PlayerPos , _gameState :: StateVar GameState } Labyrinth game Free monadic scenario
  • 7. 7 printLabyrinth :: AppState -> LangL () printLabyrinth state = do lab <- readVarIO (state ^. labyrinth) plPos <- readVarIO (state ^. playerPos) let labRender = renderLabyrinth lab plPos printLabyrinthRender labRender data AppState = AppState { _labyrinth :: StateVar Labyrinth , _playerPos :: StateVar PlayerPos , _gameState :: StateVar GameState } -- | Concurrent variable newtype StateVar a = StateVar { _varId :: Int } Labyrinth game
  • 8. 8 printLabyrinth :: AppState -> LangL () printLabyrinth state = do lab <- readVarIO (state ^. labyrinth) plPos <- readVarIO (state ^. playerPos) let labRender = renderLabyrinth lab plPos printLabyrinthRender labRender data AppState = AppState { _labyrinth :: StateVar Labyrinth , _playerPos :: StateVar PlayerPos , _gameState :: StateVar GameState } -- | Concurrent variable newtype StateVar a = StateVar { _varId :: Int } Labyrinth game Magic! (Typed Avatar pattern)
  • 9. 9 Labyrinth game labyrinthApp :: AppState -> AppL () labyrinthApp st = do scenario $ putStrLn "Labyrinth (aka Terra Incognita) game" cliToken <- cli (onStep st) (onUnknownCommand st) $ do cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight cmd "quit" $ quit st
  • 10. 10 Labyrinth game labyrinthApp :: AppState -> AppL () labyrinthApp st = do scenario $ putStrLn "Labyrinth (aka Terra Incognita) game" cliToken <- cli (onStep st) (onUnknownCommand st) $ do cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight cmd "quit" $ quit st Control Structure pattern
  • 11. 11 Labyrinth game labyrinthApp :: AppState -> AppL () labyrinthApp st = do scenario $ putStrLn "Labyrinth (aka Terra Incognita) game" cliToken <- cli (onStep st) (onUnknownCommand st) $ do cmd "go up" $ onPlayerMove st $ makePlayerMove st DirUp cmd "go down" $ onPlayerMove st $ makePlayerMove st DirDown cmd "go left" $ onPlayerMove st $ makePlayerMove st DirLeft cmd "go right" $ onPlayerMove st $ makePlayerMove st DirRight cmd "quit" $ quit st atomically $ do finished <- readVar $ cliFinishedToken cliToken when (not finished) retry Free monadic eDSL over STM Control Structure pattern
  • 13. 13 MeteorCounter app (Hydra framework) meteorsMonitoring :: AppConfig -> AppL () meteorsMonitoring cfg = do st <- atomically $ initState cfg process $ forever $ meteorCounter st process $ forever $ withRandomDelay st $ meteorShower st NorthEast process $ forever $ withRandomDelay st $ meteorShower st NorthWest process $ forever $ withRandomDelay st $ meteorShower st SouthEast process $ forever $ withRandomDelay st $ meteorShower st SouthWest atomically $ do let totalVar :: StateVar Int = _totalMeteors st total <- readVar totalVar when (total < 1000) retry
  • 14. 14 MeteorCounter app (Hydra framework) meteorsMonitoring :: AppConfig -> AppL () meteorsMonitoring cfg = do st <- atomically $ initState cfg process $ forever $ meteorCounter st process $ forever $ withRandomDelay st $ meteorShower st NorthEast process $ forever $ withRandomDelay st $ meteorShower st NorthWest process $ forever $ withRandomDelay st $ meteorShower st SouthEast process $ forever $ withRandomDelay st $ meteorShower st SouthWest atomically $ do let totalVar :: StateVar Int = _totalMeteors st total <- readVar totalVar when (total < 1000) retry Processes
  • 15. 15 MeteorCounter app (Hydra framework) meteorsMonitoring :: AppConfig -> AppL () meteorsMonitoring cfg = do st <- atomically $ initState cfg process $ forever $ meteorCounter st process $ forever $ withRandomDelay st $ meteorShower st NorthEast process $ forever $ withRandomDelay st $ meteorShower st NorthWest process $ forever $ withRandomDelay st $ meteorShower st SouthEast process $ forever $ withRandomDelay st $ meteorShower st SouthWest atomically $ do let totalVar :: StateVar Int = _totalMeteors st total <- readVar totalVar when (total < 1000) retry Finish condition
  • 16. 16 Blockchain app (Node framework) Graph Node Graph Node PoW Node TCP UDP JSON RPC
  • 17. 17 Blockchain app graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL () graphNode cfg nodeData = do let gsData = nodeData ^. graphServiceData serving Udp (cfg ^. nodeUdpPort) $ do handler $ methodPing handler $ acceptKBlock gsData process $ forever $ do awaitSignal $ gsData ^. dumpToDBSignal dumpToDB gsData process $ forever $ do awaitSignal $ gsData ^. restoreFromDBSignal restoreFromDB gsData std $ do stdHandler $ stopNodeHandler nodeData awaitNodeFinished nodeData
  • 18. 18 Blockchain app graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL () graphNode cfg nodeData = do let gsData = nodeData ^. graphServiceData serving Udp (cfg ^. nodeUdpPort) $ do handler $ methodPing handler $ acceptKBlock gsData process $ forever $ do awaitSignal $ gsData ^. dumpToDBSignal dumpToDB gsData process $ forever $ do awaitSignal $ gsData ^. restoreFromDBSignal restoreFromDB gsData std $ do stdHandler $ stopNodeHandler nodeData awaitNodeFinished nodeData UDP Service (Declarative Protocol pattern)
  • 19. 19 Blockchain app graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL () graphNode cfg nodeData = do let gsData = nodeData ^. graphServiceData serving Udp (cfg ^. nodeUdpPort) $ do handler $ methodPing handler $ acceptKBlock gsData process $ forever $ do awaitSignal $ gsData ^. dumpToDBSignal dumpToDB gsData process $ forever $ do awaitSignal $ gsData ^. restoreFromDBSignal restoreFromDB gsData std $ do stdHandler $ stopNodeHandler nodeData awaitNodeFinished nodeData Background dump / restore processes
  • 20. 20 Blockchain app graphNode :: NodeConfig GraphNode -> GraphNodeData -> NodeDefinitionL () graphNode cfg nodeData = do let gsData = nodeData ^. graphServiceData serving Udp (cfg ^. nodeUdpPort) $ do handler $ methodPing handler $ acceptKBlock gsData process $ forever $ do awaitSignal $ gsData ^. dumpToDBSignal dumpToDB gsData process $ forever $ do awaitSignal $ gsData ^. restoreFromDBSignal restoreFromDB gsData std $ do stdHandler $ stopNodeHandler nodeData awaitNodeFinished nodeData CLI & Node finish condition
  • 21. 21 Blockchain app state data GraphNodeData = GraphNodeData { _graphServiceData :: GraphServiceData , _status :: StateVar NodeStatus } data GraphServiceData = GraphServiceData { _blockchain :: BlockchainData , _db :: Maybe DBModel , _dumpToDBSignal :: StateVar Bool , _restoreFromDBSignal :: StateVar Bool , _checkPendingSignal :: StateVar Bool } Node State Node Configs Scenarios (Free monad chains) Process Process Graph Process STM transactions
  • 22. 22 Blockchain app state data GraphNodeData = GraphNodeData { _graphServiceData :: GraphServiceData , _status :: StateVar NodeStatus } data GraphServiceData = GraphServiceData { _blockchain :: BlockchainData , _db :: Maybe DBModel , _dumpToDBSignal :: StateVar Bool , _restoreFromDBSignal :: StateVar Bool , _checkPendingSignal :: StateVar Bool } awaitSignal :: (Monad m, StateIO m) => StateVar Bool -> m () awaitSignal signalVar = do atomically $ unlessM (readVar signalVar) retry writeVarIO signalVar False Signal vars
  • 23. 23 Concurrent STM-based graph Active window Request Request Request KV DB STM-based transactions
  • 24. 24 addMBlock :: WindowedGraph -> Microblock -> StateL Bool addMBlock wndGraph mblock@(Microblock hash _ _ _) = do kblock <- getKBlock wndGraph hash unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")." when (isJust kblock) $ do logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")." evalGraph wndGraph $ do newNode (MBlockContent mblock) newLink hash (MBlockContent mblock) pure $ isJust kblock Graph code sample
  • 25. 25 addMBlock :: WindowedGraph -> Microblock -> StateL Bool addMBlock wndGraph mblock@(Microblock hash _ _ _) = do kblock <- getKBlock wndGraph hash unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")." when (isJust kblock) $ do logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")." evalGraph wndGraph $ do newNode (MBlockContent mblock) newLink hash (MBlockContent mblock) pure $ isJust kblock Graph code sample STM-like transaction eDSL newVar readVar writeVar retry +Logger interface
  • 26. 26 addMBlock :: WindowedGraph -> Microblock -> StateL Bool addMBlock wndGraph mblock@(Microblock hash _ _ _) = do kblock <- getKBlock wndGraph hash unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")." when (isJust kblock) $ do logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")." evalGraph wndGraph $ do newNode (MBlockContent mblock) newLink hash (MBlockContent mblock) pure $ isJust kblock Graph code sample Work with graph NewNode DeleteNode NewLink DeleteLink GetNode ClearGraph
  • 27. 27 addMBlock :: WindowedGraph -> Microblock -> StateL Bool addMBlock wndGraph mblock@(Microblock hash _ _ _) = do kblock <- getKBlock wndGraph hash unless (isJust kblock) $ logInfo $ "Can't add MBlock: KBlock not found (" +|| hash ||+ ")." when (isJust kblock) $ do logInfo $ "Adding MBlock to the graph for KBlock (" +|| hash ||+ ")." evalGraph wndGraph $ do newNode (MBlockContent mblock) newLink hash (MBlockContent mblock) pure $ isJust kblock Graph code sample Logging within the transaction
  • 29. 29 spec :: Spec spec = unstableTest $ slowTest $ describe "PoW and graph node interaction" $ fromHUnitTest $ TestList [ TestLabel "Accept kblocks produced in order" $ testAcceptKblock InOrder , TestLabel "Accept kblocks produced in random order" $ testAcceptKblock RandomOrder ] testAcceptKblock :: Ordering -> Test testAcceptKblock order = TestCase $ withNodesManager $ mgr -> do void $ startNode mgr $ graphNode graphNodeTransmitterConfig waitForNode transmitterRpcAddress void $ startNode mgr $ powNode $ genPoWNodeConfig { _kblocksOrder = order} waitForNode powRpcAddress void $ makeIORpcRequest powRpcAddress $ NBlockPacketGeneration kblockCount timeGap let predicate kBlock = kBlock ^. number == kblockCount void $ makeRpcRequestWithPredicate predicate transmitterRpcAddress GetLastKBlock Testing nodes (virtual environment)
  • 30. 30 spec :: Spec spec = do around (withCoreRuntime Nothing) // Arrange $ it "generated labyrinth has correct bounds" $ runtime -> property $ withMaxSuccess 5 $ monadicIO $ do eLab <- run $ try $ runLangL runtime generateRndLabyrinth // Act case eLab of Left (err :: SomeException) -> assert False // Assert Right lab -> do let LabyrinthInfo {liBounds, liWormholes} = analyzeLabyrinth lab let (x, y) = liBounds let wms = Map.size liWormholes assert $ x * y >= 16 && x * y <= 100 assert $ (wms >= 2) && (wms <= 5) Testing the labyrinth logic (black box, property-based)
  • 31. 31 spec :: Spec spec = do around (withAppRuntime Nothing) $ // Arrange describe "Labyrinth generation tests" $ it "generateLabyrinth" $ rt -> do lab <- runLangL (_coreRuntime rt) $ generateLabyrinth (4, 4) 3 5 // Act let LabyrinthInfo {liBounds, liWormholes, liExits} = analyzeLabyrinth lab liBounds `shouldBe` (4, 4) // Assert (Map.size liWormholes) `shouldSatisfy` (x -> x >= 2 && x <= 5) (Set.size liExits) `shouldSatisfy` (x -> x >= 1 && x <= 3) Testing the labyrinth logic (black box, integration)
  • 32. How does this magic work? 32
  • 34. It works nicely. 34 Business logic code is very simple.
  • 35. It works nicely. 35 Business logic code is very simple. Testing is very simple.
  • 36. It works nicely. 36 Business logic code is very simple. Testing is very simple. Complete separation of concerns.
  • 38. 38 Performance of Free monads (dumb testing approach) Ops cnt FT FreeM ChurchM IO 10 0.265 0.222 0.223 0.227 100 0.221 0.226 0.228 0.222 1000 0.227 0.245 0.223 0.226 10000 0.229 4.106 0.227 0.224 100000 0.289 inf 0.31 0.309 1000000 0.859 inf 1.134 0.857 10000000 6.384 inf 9.507 6.413 20000000 13.734 inf 18.997 12.588 30000000 18.16 inf 28.568 17.76 flow :: IORef Int -> AppL () flow ref = scenario $ do val' <- evalIO $ readIORef ref val <- getRandomInt (1, 100) evalIO $ writeIORef ref $ val' + val scenario :: Int -> AppRuntime -> IO () scenario ops appRt = do ref <- newIORef 0 void $ startApp appRt (replicateM_ ops $ flow ref) val <- readIORef ref print val $ time PerfTestApp2 https://github.com/graninas/Hydra/tree/master/app/PerfTestApp2
  • 39. The truths I learned
  • 45. Performance Perfection Correctness Math Beauty Technologies Belief Good Design Getting Things Done Tests Simplicity People Experiment > > > > > >
  • 46. 46 GitHub List: Software Design in Haskell https://github.com/graninas/software-design-in-haskell👉 Hydra: framework for backend & console apps https://github.com/graninas/Hydra👉 Node: framework for distributed apps & blockchains https://github.com/graninas/Node👉
  • 47. graninas@gmail.com graninas graninas_channel StrangeMooder granin.alexander Alexander Granin 47 Free monads STM http://leanpub.com/functional-design-and-archit ecture/c/4vpQNPcmRfo1 66% discount ($60 $20) (expires 2020-08-05)
  • 48. 48 Additional Materials ● Automatic White-Box Testing with Free Monads | Article, Showcase ● Hierarchical Free Monads and Software Design in Haskell | Talk ● Hierarchical Free Monads: The Most Developed Approach In Haskell ● Functional Design and Architecture | Book ● Hydra | Framework (web services with SQL/KV DB and concurrency) ● Node | Framework (distributed apps with KV DB and concurrency) ● Final Tagless vs Free Monads | Talk ● Software Design in Haskell | List of materials
  • 49. No, really, how does this magic work? 49
  • 50. 50 Hydra Framework Implementation & Runtime Interfaces (Hierarchical Free Monad eDSLs) Domain & Business Logic ProcessL Runtime, Interpreters, Configs, Environment Application Domain Model Business Logic DB Model AppL SqlDBL LangL Beam LoggerL StateL
  • 51. 51 newtype StateVar a = StateVar { _varId :: Int } data StateF next where NewVar :: a -> (StateVar a -> next) -> StateF next ReadVar :: StateVar a -> (a -> next) -> StateF next WriteVar :: StateVar a -> a -> (() -> next) -> StateF next Retry :: (a -> next) -> StateF next EvalGraph :: TGraph c -> Free (HGraphF (TNodeL c)) x -> (x -> next) -> StateF next EvalDelayedLogger :: LoggerL () -> (() -> next) -> StateF next type StateL = Free StateF STM-like Free interface
  • 52. 52 STM-like Free language -> STM newVar' :: StateRuntime -> a -> STM VarId newVar' stateRt !a = do nodeState <- takeTMVar $ stateRt ^. state varId <- getVarId stateRt tvar <- newTVar $ unsafeCoerce a let !newMap = Map.insert varId (VarHandle tvar) nodeState putTMVar (stateRt ^. state) newMap pure varId interpretStateF :: StateRuntime -> StateF a -> STM a interpretStateF _ (Retry _) = retry interpretStateF stateRt (NewVar !val next) = do var <- newVar' stateRt val pure $ next $ StateVar var runStateL :: StateRuntime -> StateL a -> STM a runStateL stateRt = foldFree (interpretStateF stateRt)
  • 53. 53 Container language data LangF next where EvalLogger :: LoggerL () -> (() -> next) -> LangF next EvalIO :: IO a -> (a -> next) -> LangF next ... EvalStateAtomically :: StateL a -> (a -> next) -> LangF next type LangL = Free LangF atomically :: StateL a -> LangL a atomically action = liftF $ EvalStateAtomically action id
  • 54. 54 Upper level language -> IO interpretLangF :: CoreRuntime -> LangF a -> IO a interpretLangF coreRt (EvalStateAtomically action next) = do let stateRt = coreRt ^. stateRuntime let logHndl = coreRt ^. loggerRuntime . hsLoggerHandle res <- atomically $ runStateL stateRt action flushStmLogger (stateRt ^. stmLog) logHndl pure $ next res interpretLangF _ (EvalIO f next) = do !r <- f pure $ next r interpretLangF coreRt (EvalLogger loggerAct next) = next <$> runLoggerL (coreRt ^. loggerRuntime . hsLoggerHandle) loggerAct
  • 55. 55 Behind the scenes... newtype VarHandle = VarHandle (TVar Any) data StateRuntime = StateRuntime { _varId :: TVar VarId -- ^ Var id counter , _state :: TMVar (Map VarId VarHandle) -- ^ Tracked variables , _stmLog :: TVar Log -- ^ Stm log entries } data CoreRuntime = CoreRuntime { _stateRuntime :: StateRuntime , _rocksDBs :: RocksDBHandles , _redisConns :: RedisConnections , _loggerRuntime :: LoggerRuntime , _processRuntime :: ProcessRuntime , _sqlConns :: MVar (Map ConnTag NativeSqlConn) , _httpClientManager :: Manager , _cmdVerbosity :: CmdVerbosity }