intern-0.1: Data/Interned/Internal.hs
{-# LANGUAGE TypeFamilies
, FlexibleInstances
, FlexibleContexts
, GeneralizedNewtypeDeriving #-}
module Data.Interned.Internal
( Interned(..)
, mkCache
, Cache(..)
, CacheState(..)
, Id(..)
, intern
) where
import Data.Hashable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Control.Concurrent.MVar
import GHC.IO (unsafeDupablePerformIO, unsafePerformIO)
import System.Mem.Weak
data CacheState t = CacheState {-# UNPACK #-} !(Id t) (HashMap (Description t) (Weak t))
newtype Cache t = Cache { getCache :: MVar (CacheState t) }
mkCache :: Cache t
mkCache = Cache $ unsafePerformIO $ newMVar $ CacheState 0 HashMap.empty
newtype Id t = Id Int deriving (Eq,Ord,Show,Num,Real,Integral,Enum)
instance Hashable (Id t) where
hash (Id t) = hash t
hashWithSalt s (Id t) = hashWithSalt s t
class ( Eq (Description t)
, Hashable (Description t)
) => Interned t where
data Description t
type Uninterned t
describe :: Uninterned t -> Description t
unintern :: t -> Uninterned t
identify :: Id t -> Uninterned t -> t
identity :: t -> Id t
cache :: Cache t
intern :: Interned t => Uninterned t -> t
intern bt = unsafeDupablePerformIO $ modifyMVar (getCache cache) go
where
dt = describe bt
go (CacheState i m) = case HashMap.lookup dt m of
Nothing -> k i m
Just wt -> do
mt <- deRefWeak wt
case mt of
Just t -> return (CacheState i m, t)
Nothing -> k i m
k i m = do let t = identify i bt
wt <- t `seq` mkWeakPtr t $ Just remove
return (CacheState (i + 1) (HashMap.insert dt wt m), t)
remove = modifyMVar_ (getCache cache) $
\ (CacheState i m) -> return $ CacheState i (HashMap.delete dt m)
{-
type Var = Int
data Term
= App {-# UNPACK #-} !(Id Term) !Term !Term
| Lam {-# UNPACK #-} !(Id Term) {-# UNPACK #-} !Var !Term !Term
| Pi {-# UNPACK #-} !(Id Term) {-# UNPACK #-} !Var !Term !Term
| Set {-# UNPACK #-} !(Id Term) {-# UNPACK #-} !Int
deriving Show
data UninternedTerm
= BApp Term Term
| BLam Var Term Term
| BPi Var Term Term
| BSet Int deriving Show
instance Interned Term where
type Uninterned Term = UninternedTerm
data Description Term = DApp (Id Term) (Id Term)
| DLam Var (Id Term) (Id Term)
| DPi Var (Id Term) (Id Term)
| DSet Int deriving Show
describe (BApp f a) = DApp (identity f) (identity a)
describe (BLam v t e) = DLam v (identity t) (identity e)
describe (BPi v t e) = DPi v (identity t) (identity e)
describe (BSet n) = DSet n
identify i = go where
go (BApp f a) = App i f a
go (BLam v t e) = Lam i v t e
go (BPi v t e) = Pi i v t e
go (BSet n) = Set i n
identity (App i _ _) = i
identity (Lam i _ _ _) = i
identity (Pi i _ _ _) = i
identity (Set i _) = i
unintern (App _ f a) = BApp f a
unintern (Lam _ v t e) = BLam v t e
unintern (Pi _ v t e) = BPi v t e
unintern (Set _ n) = BSet n
cache = termCache
termCache :: Cache Term
termCache = mkCache
{-# NOINLINE termCache #-}
instance Eq (Description Term) where
DApp f a == DApp f' a' = f == f' && a == a'
DLam v t e == DLam v' t' e' = v == v' && t == t' && e == e'
DPi v t e == DPi v' t' e' = v == v' && t == t' && e == e'
DSet n == DSet n' = n == n'
_ == _ = False
instance Hashable (Description Term) where
hash (DApp f a) = 0 `hashWithSalt` f `hashWithSalt` a
hash (DLam v t e) = 1 `hashWithSalt` v `hashWithSalt` t `hashWithSalt` e
hash (DPi v t e) = 2 `hashWithSalt` v `hashWithSalt` t `hashWithSalt` e
hash (DSet n) = 3 `hashWithSalt` n
instance Eq Term where
(==) = (==) `on` identity
instance Ord Term where
compare = compare `on` identity
app :: Term -> Term -> Term
app a b = intern (BApp a b)
lam :: Var -> Term -> Term -> Term
lam v t e = intern (BLam v t e)
pi :: Var -> Term -> Term -> Term
pi v t e = intern (BPi v t e)
set :: Int -> Term
set i = intern (BSet i)
-}