summaryrefslogtreecommitdiff
path: root/src/Sequence/Formula.hs
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-06-06 02:41:09 +0200
committerGregor Kleen <gkleen@yggdrasil.li>2016-06-06 02:41:09 +0200
commit54624cecd73a0b1ae3b8c6de41808ca02b31179e (patch)
treeadebeb88499749969e6f56e10ddf3347c219b3ed /src/Sequence/Formula.hs
parentb0460c33fe676912b88de09f49956a4adf5c9752 (diff)
download2017-01-16_17:13:37-54624cecd73a0b1ae3b8c6de41808ca02b31179e.tar
2017-01-16_17:13:37-54624cecd73a0b1ae3b8c6de41808ca02b31179e.tar.gz
2017-01-16_17:13:37-54624cecd73a0b1ae3b8c6de41808ca02b31179e.tar.bz2
2017-01-16_17:13:37-54624cecd73a0b1ae3b8c6de41808ca02b31179e.tar.xz
2017-01-16_17:13:37-54624cecd73a0b1ae3b8c6de41808ca02b31179e.zip
Evaluate formulas in arbitrarily large context
Diffstat (limited to 'src/Sequence/Formula.hs')
-rw-r--r--src/Sequence/Formula.hs38
1 files changed, 29 insertions, 9 deletions
diff --git a/src/Sequence/Formula.hs b/src/Sequence/Formula.hs
index 0d99fc0..9000c58 100644
--- a/src/Sequence/Formula.hs
+++ b/src/Sequence/Formula.hs
@@ -1,13 +1,14 @@
1{-# LANGUAGE RecordWildCards, RankNTypes, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, ViewPatterns, TypeFamilies #-} 1{-# LANGUAGE RecordWildCards, RankNTypes, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, ViewPatterns, TypeFamilies, GADTs, TypeOperators, ExistentialQuantification, FlexibleContexts #-}
2 2
3module Sequence.Formula 3module Sequence.Formula
4 ( FormulaM, Formula, quot' 4 ( FormulaM, Formula, quot'
5 , (:<:)(..), Context(..)
5 , evalFormula 6 , evalFormula
6 , val 7 , val
7 , d, z 8 , d, z
8 ) where 9 ) where
9 10
10import Control.Lens 11import Control.Lens hiding (Context(..))
11import Data.Data.Lens 12import Data.Data.Lens
12 13
13import Control.Monad 14import Control.Monad
@@ -30,8 +31,27 @@ import Data.Either
30import Data.Set (Set) 31import Data.Set (Set)
31import qualified Data.Set as Set 32import qualified Data.Set as Set
32 33
34class (:<:) small large where
35 ctx' :: Traversal' large small
33 36
34type FormulaM input a = StateT (Set String) (ReaderT input (ExceptT (Question input) EventM)) a 37instance a :<: a where
38 ctx' = simple
39
40instance a :<: (a, a) where
41 ctx' = both
42
43instance a :<: (a, b) where
44 ctx' = _1
45
46instance a :<: (b, a) where
47 ctx' = _2
48
49data Context small = forall large. (small :<: large) => Context large
50
51ctx :: Traversal' (Context input) input
52ctx modifySmall (Context large) = Context <$> ctx' modifySmall large
53
54type FormulaM input a = StateT (Set String) (ReaderT (Context input) (ExceptT (Question input) EventM)) a
35 55
36type Formula input = FormulaM input Int 56type Formula input = FormulaM input Int
37 57
@@ -66,22 +86,22 @@ instance Integral a => Num (FormulaM input a) where
66quot' :: Integral a => FormulaM input a -> FormulaM input a -> FormulaM input a 86quot' :: Integral a => FormulaM input a -> FormulaM input a -> FormulaM input a
67quot' = liftM2 quot 87quot' = liftM2 quot
68 88
69askQuestion :: MonadIO m => input -> (Question input) -> m input 89askQuestion :: (MonadIO m, sInput :<: lInput) => lInput -> Question sInput -> m lInput
70askQuestion input q@(Question{..}) = flip (set answer) input . maybe (throwError q) return <$> askQ prompt (join . fmap readMaybe) 90askQuestion input q@(Question{..}) = flip (set $ ctx' . answer) input . maybe (throwError q) return <$> askQ prompt (join . fmap readMaybe)
71 91
72evalFormula :: (MonadIO m, Ord a, Show a) => input -> FormulaM input a -> m (input, a) 92evalFormula :: (MonadIO m, sInput :<: lInput) => lInput -> FormulaM sInput a -> m (lInput, a)
73evalFormula = evalFormula' [] 93evalFormula = evalFormula' []
74 where 94 where
75 evalFormula' finalChanges input formula = do 95 evalFormula' finalChanges input formula = do
76 result <- liftIO . enact . runExceptT . (runReaderT ?? input) . (evalStateT ?? Set.empty) $ formula 96 result <- liftIO . enact . runExceptT . (runReaderT ?? (Context input)) . (evalStateT ?? Set.empty) $ formula
77 case result of 97 case result of
78 Left q@(Question{..}) -> askQuestion input q >>= flip (evalFormula' $ bool (pure . set answer $ throwError q) mempty keepResult ++ finalChanges) formula 98 Left q@(Question{..}) -> askQuestion input q >>= flip (evalFormula' $ bool (pure . set (ctx' . answer) $ throwError q) mempty keepResult ++ finalChanges) formula
79 Right result -> return (foldr ($) input finalChanges, result) 99 Right result -> return (foldr ($) input finalChanges, result)
80 100
81val :: Integral a => Traversal' input (Formula input) -> String -> Bool -> Formula input 101val :: Integral a => Traversal' input (Formula input) -> String -> Bool -> Formula input
82val answer prompt keepResult = do 102val answer prompt keepResult = do
83 gets (Set.member prompt) >>= bool (modify $ Set.insert prompt) (modify (Set.delete prompt) >> throwError Question{..}) 103 gets (Set.member prompt) >>= bool (modify $ Set.insert prompt) (modify (Set.delete prompt) >> throwError Question{..})
84 preview answer >>= maybe (throwError Question{..}) id 104 preview (ctx . answer) >>= maybe (throwError Question{..}) id
85 105
86d, z :: Integral a => Int -> FormulaM input a 106d, z :: Integral a => Int -> FormulaM input a
87d n = liftBase . fmap fromIntegral $ D.d n 107d n = liftBase . fmap fromIntegral $ D.d n