packages feed

ghci4luatex-0.0: src/Data/Memoizer/Sessions.hs

--------------------------------------------------------------------------------
-- |
--
-- Module      :  Data.Memoizer.Session
-- Description :  Sessions for command memoizers
-- Copyright   :  (c) Alice Rixte 2024
-- License     :  BSD 3
-- Maintainer  :  alice.rixte@u-bordeaux.fr
-- Stability   :  unstable
-- Portability :  portable
--
-- Memoize several sessions and switch between them.
--
-- This enables the use of the @\\ghcisession{My Session}@ and
-- @\\ghcicontinue{My Session}@ command in the @ghci@ LuaTex package.
--
-- = Usage
--
--
-- Let us store the result of some commands (we alternate between @memo@ and
-- @memo'@ to avoid recursive definitions)
--
-- >>> import Prelude hiding (lookup)
--
-- >>> memo = initSession "main" :: SessionMemoizer String String String
-- >>> memo' = storeResult "x=1" "" memo
-- >>> memo = storeResult "y=2" "" memo'
-- >>> memo' = storeResult "x+y" "3" memo
--
-- Let use create a new session:
--
-- >>> memo = newSession "My Session" memo'
-- >>> memo' = storeResult "a=1" "" memo
--
-- Now if we create a new session called "main" again, we can use the memoized
-- values:
--
-- >>> memo = newSession "main" memo'
-- >>> lookup "x=1" memo
-- Just ""
--
--
-- But we still have some commands to add to "My Session":
--
-- >>> memo' = continueSession "My Session" memo
-- >>> memo = storeResult "a" "1" memo'
--
-- Now let's restart "My Session":
--
-- >>> memo' = newSession "My Session" memo
-- >>> lookup "a=1" memo
-- Just ""
-- >>> memo = nextCmd memo'
-- >>> lookup "a" memo
-- Just "1"
--
--------------------------------------------------------------------------------

module Data.Memoizer.Sessions
  ( SessionMemoizer (..)
  , initSession
  , newSession
  , continueSession
  , storeResult
  , deleteResult
  , lookup
  , nextCmd
  ) where

import Prelude hiding (lookup)
import qualified Data.Memoizer.Commands as Cmd
import qualified Data.Map as Map

-- | A container of  memoizers for sequences of commands.
--
-- * @k@ is the key representing the name of a session
-- * @a@ is the type of commands
-- * @b@ is the result of a command
--
data SessionMemoizer k a b = SessionMemoizer
  { sessionMap :: Map.Map k (Cmd.CmdMemoizer a b)
  , currentSession :: k
  }
  deriving (Show,Eq)

undefinedSession :: String
undefinedSession = "UndefinedSession : The current Session does not exist.\
  \ This should never happen. Please report this as a bug."

lookupCmd :: Ord k => SessionMemoizer k a b -> Cmd.CmdMemoizer a b
lookupCmd (SessionMemoizer ms k) = case Map.lookup k ms of
  Nothing -> error $ "lookup : " ++ undefinedSession
  Just m -> m

mapCmd :: Ord k =>
  (Cmd.CmdMemoizer a b -> Cmd.CmdMemoizer a b)
  -> SessionMemoizer k a b -> SessionMemoizer k a b
mapCmd f sm@(SessionMemoizer ms k) =
  sm {sessionMap = Map.insert k (f (lookupCmd sm)) ms }

-------------------------------------------------------------------------------

-- | Create a new session memoizer using a default session.
--
initSession :: Ord k => k -> SessionMemoizer k a b
initSession k = SessionMemoizer (Map.insert k Cmd.empty Map.empty) k

-- | Add a new session to memoize. If that session already existes, it is
-- @'Data.Memoizer.Commands.restart'@ed.
--
newSession :: Ord k => k -> SessionMemoizer k a b -> SessionMemoizer k a b
newSession k (SessionMemoizer ms _) =
  case Map.lookup k ms of
    Nothing -> SessionMemoizer (Map.insert k Cmd.empty ms) k
    Just m -> SessionMemoizer (Map.insert k (Cmd.restart m) ms) k

-- | Continue an existing session.
--
continueSession :: Ord k => k -> SessionMemoizer k a b -> SessionMemoizer k a b
continueSession k m = m {currentSession = k}

-- | Lookup the memoized result of the current session.
--
lookup :: (Eq a, Ord k) => a -> SessionMemoizer k a b -> Maybe b
lookup a  = Cmd.lookup a . lookupCmd

-- | Move the current session to the next command.
--
nextCmd :: Ord k => SessionMemoizer k a b -> SessionMemoizer k a b
nextCmd = mapCmd Cmd.nextCmd

-- | Store a result in the current session.
--
-- This will prevent access to any memoized result of the current session until
-- @'newSession'@ is used.
--
storeResult :: Ord k => a -> b -> SessionMemoizer k a b -> SessionMemoizer k a b
storeResult a b = mapCmd (Cmd.storeResult a b)

-- | Delete the current result in the current session.
--
-- This will prevent access to any memoized result  of the current session until
-- @'newSession'@ is used.
--
deleteResult :: Ord k
  =>  SessionMemoizer k a b -> SessionMemoizer k a b
deleteResult = mapCmd Cmd.deleteResult