{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveFunctor #-} -- | All `Context`-related operations module Morte.Context ( -- * Context Context , empty , insert , lookup , toList ) where import Control.DeepSeq (NFData) import Data.Text.Lazy (Text) import Prelude hiding (lookup) {-| Bound variable names and their types Variable names may appear more than once in the `Context`. The `Var` @x\@n@ refers to the @n@th occurrence of @x@ in the `Context` (using 0-based numbering). -} newtype Context a = Context { getContext :: [(Text, a)] } deriving (Functor, NFData) {-| An empty context with no key-value pairs > toList empty = [] -} empty :: Context a empty = Context [] -- | Add a key-value pair to the `Context` insert :: Text -> a -> Context a -> Context a insert k v (Context kvs) = Context ((k, v) : kvs) {-# INLINABLE insert #-} {-| Lookup a key by name and index > lookup k 0 (insert k v0 ctx ) = Just v0 > lookup k 1 (insert k v0 (insert k v1 ctx)) = Just v1 -} lookup :: Text -> Int -> Context a -> Maybe a lookup k n0 (Context kvs0) = loop kvs0 n0 where loop ((k', v):kvs) n | k /= k' = loop kvs n | n > 0 = loop kvs $! n - 1 | n == 0 = Just v | otherwise = Nothing loop [] _ = Nothing {-# INLINABLE lookup #-} -- | Return all key-value associations as a list toList :: Context a -> [(Text, a)] toList = getContext {-# INLINABLE toList #-}