summaryrefslogtreecommitdiff
path: root/src/Sequence/Formula.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Sequence/Formula.hs')
-rw-r--r--src/Sequence/Formula.hs46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/Sequence/Formula.hs b/src/Sequence/Formula.hs
new file mode 100644
index 0000000..7a6e689
--- /dev/null
+++ b/src/Sequence/Formula.hs
@@ -0,0 +1,46 @@
1{-# LANGUAGE RecordWildCards, RankNTypes, TypeSynonymInstances, FlexibleInstances #-}
2
3module Sequence.Formula
4 ( FormulaM
5 , evalFormula
6 , val
7 ) where
8
9import Control.Lens
10
11import Control.Monad.Trans.Either
12import Control.Monad.Reader
13import Numeric.Probability.Game.Event
14
15import Sequence.Utils
16
17import Text.Read (readMaybe)
18
19type FormulaM input a = ReaderT input (EitherT (Question input) EventM) a
20
21data Question input = Question
22 { answer :: Lens' input (Maybe Int)
23 , prompt :: String
24 }
25
26instance Integral a => Num (FormulaM input a) where
27 (+) x y = (+) <$> x <*> y
28 (-) x y = (-) <$> x <*> y
29 negate = fmap negate
30 abs = fmap abs
31 signum = fmap signum
32 (*) x y = sum <$> (flip replicateM y =<< fromIntegral <$> x)
33 fromInteger = return . fromInteger
34
35askQuestion :: MonadIO m => input -> (Question input) -> m input
36askQuestion input q@(Question{..}) = flip (set answer) input <$> askQ prompt (join . fmap readMaybe)
37
38evalFormula :: MonadIO m => input -> FormulaM input a -> m a
39evalFormula input formula = do
40 result <- liftIO . enact . runEitherT . (runReaderT ?? input) $ formula
41 case result of
42 Left q -> askQuestion input q >>= flip evalFormula formula
43 Right result -> return result
44
45val :: Integral a => Lens' input (Maybe Int) -> String -> FormulaM input Int
46val answer prompt = view answer >>= maybe (lift . left $ Question{..}) return