let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result around{fact} (arg) = \acc -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result"> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result around{fact} (arg) = \acc -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result">
Download presentation
Presentation is loading. Please wait.
Published byIris Amberly Webb Modified over 9 years ago
1
Stateful Aspects Monitoring and Lazy Semantics
2
Base program fact :: Int -> Int -> Int fact :: Int -> Int -> Int fact n acc = if n == 0 then acc else fact (n - 1) (acc * n) fact n acc = if n == 0 then acc else fact (n - 1) (acc * n) Purely functional Purely functional Don ’ t know the existence of imperative monitor Don ’ t know the existence of imperative monitor
3
Aspects and Syntactic Sugar var indent :: String = "" var indent :: String = "" monitor@aspect around{fact} (arg) = \acc -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result monitor@aspect around{fact} (arg) = \acc -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++"fact is call with " ++ show arg; let result = proceed arg acc in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result
4
Aspects and Syntactic Sugar (cont.) times_monitor@aspect around{(*)} (lhs) = \rhs -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++ show lhs ++ " times " ++ show rhs ++ " is called"; let result = proceed lhs rhs in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result times_monitor@aspect around{(*)} (lhs) = \rhs -> let ind = getIndent setIndent ("| " ++ ind); putMsg $ ind ++ show lhs ++ " times " ++ show rhs ++ " is called"; let result = proceed lhs rhs in setIndent ind; putMsg $ ind ++ "`returns " ++ show result; result
5
Desugared UserState data UserState = U{ indent :: String } deriving Show data UserState = U{ indent :: String } deriving Show emptyUserState = U{ indent = "" } emptyUserState = U{ indent = "" } getIndent :: S String getIndent :: S String getIndent = getUserState >>= \u -> return $ indent u getIndent = getUserState >>= \u -> return $ indent u setIndent :: String -> S () setIndent :: String -> S () setIndent ind = modifyUserState $ \u -> u{ indent = ind } setIndent ind = modifyUserState $ \u -> u{ indent = ind }
6
API for Accessing Internal State type S a = State (UserState, InternalState) a type S a = State (UserState, InternalState) a type M a = S a type M a = S a runM = runState runM = runState emptyM = (emptyUserState, emptyInternalState) emptyM = (emptyUserState, emptyInternalState) type InternalState = [String] type InternalState = [String] emptyInternalState = [] emptyInternalState = [] putMsg :: String -> M () putMsg :: String -> M () putMsg str = modify $ \(u, s) -> (u, str:s) putMsg str = modify $ \(u, s) -> (u, str:s) putMsgs :: [String] -> M () putMsgs :: [String] -> M () putMsgs strs = modify $ \(u, s) -> (u, strs ++ s) putMsgs strs = modify $ \(u, s) -> (u, strs ++ s) getUserState :: M UserState getUserState :: M UserState getUserState = gets fst getUserState = gets fst modifyUserState :: (UserState -> UserState) -> M () modifyUserState :: (UserState -> UserState) -> M () modifyUserState trans = modify $ \(u, s) -> (trans u, s) modifyUserState trans = modify $ \(u, s) -> (trans u, s)
7
Translated Advice (orig.) times_monitor :: M (M Int -> M (M Int -> M Int)) -> M (M Int -> M (M Int -> M Int)) times_monitor :: M (M Int -> M (M Int -> M Int)) -> M (M Int -> M (M Int -> M Int)) times_monitor proceed = return $ \lhs -> return $ \rhs -> do ind return $ \rhs -> do ind <- getIndent setIndent ("| " ++ ind) lhs' <- lhs; rhs' <- rhs putMsg $ ind ++ show lhs' ++ " times " ++ show rhs' ++ " is called" p <- proceed; p' <- p lhs; result <- p' rhs setIndent ind putMsg $ ind ++ "`returns " ++ show result return result Bind out for every applica- tion
8
Translated Base Program fact_chain :: M (M Int -> M (M Int -> M Int)) fact_chain :: M (M Int -> M (M Int -> M Int)) fact_chain = monitor fact_body -- fact_chain = monitor fact_body -- fact_body :: M (M Int -> M (M Int -> M Int)) fact_body :: M (M Int -> M (M Int -> M Int)) fact_body = return $ \n -> return $ \acc -> let eq a b = a >>= \a' -> b >>= \b' -> return (a' == b') sub a b = a >>= \a' -> b >>= \b' -> return (a' - b') zero = return 0 one = return 1 in do eq_n_zero return $ \acc -> let eq a b = a >>= \a' -> b >>= \b' -> return (a' == b') sub a b = a >>= \a' -> b >>= \b' -> return (a' - b') zero = return 0 one = return 1 in do eq_n_zero <- eq n zero if eq_n_zero then acc else do t <- times_chain t' <- t n f <- fact_chain f' <- f (sub n one) f' (t' acc) Monadic all built-in functions and constants
9
Test Bed runFact :: Int -> (Int, (UserState, [String])) runFact :: Int -> (Int, (UserState, [String])) runFact n = runM (do f <- fact_chain f' <- f (return n) f' (return 1) ) emptyM runFact n = runM (do f <- fact_chain f' <- f (return n) f' (return 1) ) emptyM
10
Montor Result (orig.) *Main> mapM_ putStrLn $ reverse $ snd $ snd $ runFact 3 fact is call with 3 | fact is call with 2 | | fact is call with 1 | | | fact is call with 0 | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | 2 times 3 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | 1 times 6 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | 2 times 3 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | `returns 6 | | | `returns 6 | | `returns 6 | `returns 6 `returns 6 Result from the lhs' <- lhs; rhs' <- rhs putMsg $ ind ++ show lhs' ++ " times " ++ show rhs' ++ " is called"
11
Solution Viewing "M a" as a "thunk" holding a value typed "a", the solution is to build updatable thunks. Viewing "M a" as a "thunk" holding a value typed "a", the solution is to build updatable thunks. Well known way to do so: Well known way to do so: Environment mapping variables (names) to locationsEnvironment mapping variables (names) to locations Store is updatable.Store is updatable. (M a) holds an integer (M a) holds an integer A store passed inside monad A store passed inside monad
12
CState: Cached State Monad import qualified Data.Map as M import qualified Data.Map as M newtype CState s a = CState{ realrunCState :: (s, CacheSet) -> (Either a Int, (s, CacheSet)) } newtype CState s a = CState{ realrunCState :: (s, CacheSet) -> (Either a Int, (s, CacheSet)) } data Cell = forall s a. Cell Bool (CState s a) -- Cell Ever_used Thunk data Cell = forall s a. Cell Bool (CState s a) -- Cell Ever_used Thunk type CacheSet = M.Map Int (Maybe Cell) type CacheSet = M.Map Int (Maybe Cell) If (cs :: CState s a) (st, ca) = Right i If (cs :: CState s a) (st, ca) = Right i then (lookup i ca) has the form Just (Just (Cell b (ca :: (CState s a))))then (lookup i ca) has the form Just (Just (Cell b (ca :: (CState s a)))) It exists, and the value in it has the same type.It exists, and the value in it has the same type.
13
CState (cont.) instance Monad (CState s) instance Monad (CState s) instance MonadState s (CState s) instance MonadState s (CState s) getNewCache :: CState Int getNewCache :: CState Int mkCache :: Int -> CState s a -> CState s a mkCache :: Int -> CState s a -> CState s a fromCell :: Cell -> (s, CacheSet) -> (Either a Int, (s, CacheSet)) fromCell :: Cell -> (s, CacheSet) -> (Either a Int, (s, CacheSet)) Used GHC.Prim.unsafeCoarce#Used GHC.Prim.unsafeCoarce# fromCacheEither :: Either a Int -> (s, CacheSet) -> (a, (s, CacheSet)) fromCacheEither :: Either a Int -> (s, CacheSet) -> (a, (s, CacheSet))
14
Translated Advice (with CState) times_monitor proceed = return $ \lhs -> getNewCache >>= \cacheN -> return $ \rhs -> mkCache cacheN $ do ind getNewCache >>= \cacheN -> return $ \rhs -> mkCache cacheN $ do ind <- getIndent …… t <- times_chain t' <- t n f' (t' acc) t <- times_chain t' <- t n f' (t' acc) Allocate cache location before consuming the last argument Put the monad into the location Location allocated Thunk made, location filled
15
Monitor Result (with CState) *Main> mapM_ putStrLn $ reverse $ snd $ snd $ runFact 3 fact is call with 3 | fact is call with 2 | | fact is call with 1 | | | fact is call with 0 | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | 2 times 3 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | 1 times 6 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | 2 times 3 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | `returns 6 | | | `returns 6 | | `returns 6 | `returns 6 `returns 6 Result from the lhs' <- lhs; rhs' <- rhs putMsg $ ind ++ show lhs' ++ " times " ++ show rhs' ++ " is called" Multiplication result cached, thus not do the “ times ” body twice.
16
Resolving the advice interference showM :: M Int -> String showM :: M Int -> String showM :: (M Int -> M String) is more natural but complicated to useshowM :: (M Int -> M String) is more natural but complicated to use unserialize :: CacheSet -> String -> String unserialize :: CacheSet -> String -> String Find the substrings encoded by showM and decode by the CacheSetFind the substrings encoded by showM and decode by the CacheSet
17
Translated Advice (final) times_monitorM :: M (M Int -> M (M Int -> M Int)) -> M (M Int -> M (M Int -> M Int)) times_monitorM :: M (M Int -> M (M Int -> M Int)) -> M (M Int -> M (M Int -> M Int)) times_monitorM proceed = return $ \lhs -> getNewCache >>= \cacheN -> return $ \rhs -> mkCache cacheN $ do ind getNewCache >>= \cacheN -> return $ \rhs -> mkCache cacheN $ do ind <- getIndent setIndent ("| " ++ ind) putMsg $ ind ++ showM lhs ++ " times " ++ showM rhs ++ " is called" p <- proceed; p' <- p lhs; result <- p' rhs setIndent ind putMsg $ ind ++ "`returns " ++ show result return result
18
Monitor Result (final) *Main> mapM_ putStrLn $ reverse $ snd $ snd $ runFactM 3 fact is call with 3 | fact is call with 2 | | fact is call with 1 | | | fact is call with 0 | | | | 1 times 6 is called | | | | | 2 times 3 is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | `returns 6 | | | `returns 6 | | `returns 6 | `returns 6 `returns 6 *Main> mapM_ putStrLn $ reverse $ snd $ snd $ runFactM' 3 fact is call with 3 | fact is call with 2 | | fact is call with 1 | | | fact is call with 0 | | | | 1 times <M'M:5| is called | | | | | 2 times <M'M:2| is called | | | | | | 3 times 1 is called | | | | | | `returns 3 | | | | | `returns 6 | | | | `returns 6 | | | `returns 6 | | `returns 6 | `returns 6 `returns 6
19
TODOs Cooperating with Cflow ’ s reader monad Cooperating with Cflow ’ s reader monad Use ReaderTUse ReaderT Formalize translation rules Formalize translation rules Type translation is now like:Type translation is now like: T(a -> b) = M (T(a) -> T(b)) T(a -> b) = M (T(a) -> T(b)) T(t) = M t T(t) = M t Expression translationExpression translation let => bind let => bind Function app. => bind out function first Function app. => bind out function first Lifting built-in functions and constants Lifting built-in functions and constants
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.