Composable monadic STM for C++ on Free monads
Working library for Software Transactional Memory that is built using several FP techniques and modern C++17.
Additional materials
retry
satisfiable.The simplest possible usage is int counter increment from different threads.
Transaction:
stm::STML<int> incrementCounter(const stm::TVar<int>& tCounter) {
stm::STML<stm::Unit> modified =
stm::modifyTVar<int>(tCounter, [](int i) { return i + 1; });
return stm::bind<stm::Unit, int>(modified,
[&](const stm::Unit&){ return stm::readTVar<int>(tCounter); });
}
Evaluation:
Context ctx;
stm::TVar<int> tCounter = stm::newTVarIO(ctx, 0);
int counter = stm::atomically(ctx, incrementCounter(tCounter));
std::cout << "Counter: " << counter << std::endl;
The Dining Philosopher Problem
can be solved with STM elegantly. Here are the transactions for taking of forks:
stm::STML<stm::Unit> takeFork(const TFork& tFork) {
return stm::withTVar<Fork, stm::Unit>(tFork, [=](const Fork& fork) {
if (fork.state == ForkState::Free) {
return stm::writeTVar<Fork>(tFork, Fork { fork.name, ForkState::Taken });
}
else {
return stm::retry<stm::Unit>();
}
});
}
stm::STML<stm::Unit> takeForks(const TForkPair& forks) {
stm::STML<stm::Unit> lm = takeFork(forks.left);
stm::STML<stm::Unit> rm = takeFork(forks.right);
return stm::sequence(lm, rm);
}
Notice the retry
combinator that marks some state illegal and makes the transaction to restart on case if fork was already taken.
To get more information, read the tutorial.