## Software Transactional Memory examples


[Documentation for STM](https://hackage.haskell.org/package/stm-2.4.4/docs/Control-Monad-STM.html)

[Documentation - TMVar](https://hackage.haskell.org/package/stm-2.4.4/docs/Control-Concurrent-STM-TMVar.html)

[A presentation on Haskell and STM in particular](http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/STMTokyoApr10.pdf)



## Example 1


```active haskell
module Main where

import qualified Control.Concurrent        as CC
import qualified Control.Concurrent.STM    as T
import qualified Control.Monad             as CM

type Account = T.TMVar Float

openAccount :: Float -> T.STM (Account)
openAccount balance = T.newTMVar balance

getBalance :: Account -> T.STM Float
getBalance account = do
    balance <- T.takeTMVar account
    return balance

main :: IO ()
main = do
    accountA <- T.atomically (openAccount 20)
    balanceA <- T.atomically $ getBalance accountA
    print $ balanceA
```


## Example 2


```active haskell
module Main where

import qualified Control.Concurrent.STM    as T

type Account = T.TMVar Float

openAccount :: Float -> T.STM (Account)
openAccount balance = T.newTMVar balance

transfer :: Account -> Account -> Float -> T.STM Float
transfer accountA accountB amount = do
    startingBalanceA <- T.takeTMVar accountA
    startingBalanceB <- T.takeTMVar accountB

    let finalBalanceA = (startingBalanceA - amount)
    let finalBalanceB = (startingBalanceB + amount)

    T.putTMVar accountA finalBalanceA
    T.putTMVar accountB finalBalanceB

    return $ amount

main :: IO ()
main = do
    accountA <- T.atomically (openAccount 20)
    accountB <- T.atomically (openAccount 50)
    amt <- T.atomically (transfer accountA accountB 30)
    print $ amt
```


## Example 3


```active haskell
module Main where


import qualified Control.Concurrent        as CC
import qualified Control.Concurrent.STM    as T
import qualified Control.Monad             as CM

type Account = T.TMVar Float
    
openAccount :: Float -> T.STM (Account)
openAccount balance = T.newTMVar balance

getBalance :: Account -> T.STM Float
getBalance account = do
    balance <- T.takeTMVar account
    return balance

transfer :: Account -> Account -> Float -> T.STM ()
transfer accountA accountB amount = do
    startingBalanceA <- T.takeTMVar accountA
    startingBalanceB <- T.takeTMVar accountB

    let finalBalanceA = (startingBalanceA - amount)
    let finalBalanceB = (startingBalanceB + amount)

    T.check (finalBalanceA >= 0)

    T.putTMVar accountA finalBalanceA
    T.putTMVar accountB finalBalanceB

takeFee :: Account -> Float -> T.STM ()
takeFee account fee = do
    startingBalance <- T.takeTMVar account
    let finalBalance = (startingBalance - fee)
    T.putTMVar account finalBalance

transferOrFee :: Account -> Account -> Float -> Float -> T.STM ()
transferOrFee accountA accountB amount dishonourFee =
    T.orElse (transfer accountA accountB amount) (takeFee accountA dishonourFee)

transferOrFee2 :: Account -> Account -> Float -> Float -> T.STM ()
transferOrFee2 accountA accountB amount dishonourFee =
    T.orElse (
        do
            T.check (amount >= 0)
            transferOrFee accountA accountB amount dishonourFee
    ) (return ())

main :: IO ()
main = do
    accountA <- T.atomically (openAccount 20)
    accountB <- T.atomically (openAccount 70)
    _ <- T.atomically (transferOrFee2 accountA accountB 30 5)
    balA <- T.atomically $ getBalance accountA
    print $ balA
    balB <- T.atomically $ getBalance accountB
    print $ balB

```

