module Acme.Money (Money, lift', charge, purchase, runMoneys) where
import Control.Monad.Reader
import Control.Monad.Trans
import Data.IORef
newtype Money u t = Money { unMoney :: ReaderT (Int, Int, [(IORef Float, Money u u)]) IO t }
instance Monad (Money u) where
return = Money . return
Money m >>= f = Money $ m >>= unMoney . f
lift' = Money . lift
charge n =
if n < 0 then
error "Charity begins at home"
else
Money (ask >>= \(i, j, ls) -> let ref = fst (ls !! j) in
lift $ readIORef ref >>= \m ->
if m >= n then
writeIORef ref (m n) >> modifyIORef (fst (ls !! i)) (+n)
else
error "Wallet lint")
purchase i = Money (ask >>= \(j, _, ls) -> lift $ runReaderT (unMoney $ snd (ls !! i)) (i, j, ls))
runMoneys ls = map (\(i, (_, m)) -> runReaderT (unMoney m) (i, 1, ls)) (zip [0..] ls)