File: TagShare.hs

package info (click to toggle)
haskell-tagshare 0.0-6
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 56 kB
  • sloc: haskell: 44; makefile: 5
file content (62 lines) | stat: -rw-r--r-- 1,535 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

-- | A monad for binding values to tags to ensure sharing, 
-- with the added twist that the value can be polymorphic
-- and each monomorphic instance is bound separately.
module Control.Monad.TagShare(
  -- ** Dynamic map
  DynMap,
  dynEmpty,
  dynInsert,
  dynLookup,
  -- ** Sharing monad
  Sharing,
  runSharing,
  share
  ) where
import Control.Monad.State
import Data.Typeable
import Data.Dynamic(Dynamic, fromDynamic, toDyn)
import Data.Map as M

-- |  A dynamic map with type safe
-- insertion and lookup.
newtype DynMap tag = 
  DynMap (M.Map (tag, TypeRep) Dynamic) 
  deriving Show

dynEmpty :: DynMap tag
dynEmpty = DynMap M.empty  
  
dynInsert :: (Typeable a, Ord tag) => 
                tag -> a -> DynMap tag -> DynMap tag
dynInsert u a (DynMap m) = 
          DynMap (M.insert (u,typeOf a) (toDyn a) m)

dynLookup :: (Typeable a, Ord tag) => 
                tag -> DynMap tag -> Maybe a
dynLookup u (DynMap m) = hlp fun undefined where 
    hlp :: Typeable a => 
      (TypeRep -> Maybe a) -> a -> Maybe a
    hlp f a = f (typeOf a)
    fun tr = M.lookup (u,tr) m >>= fromDynamic

 
-- | A sharing monad
-- with a function that binds a tag to a value.
type Sharing tag a = State (DynMap tag) a

runSharing :: Sharing tag a -> a
runSharing m = evalState m dynEmpty

share :: (Typeable a, Ord tag) => 
  tag -> Sharing tag a -> Sharing tag a
share t m = do
    mx <- gets $ (dynLookup t)
    case mx of
      Just e      ->  return e
      Nothing     ->  mfix $ \e -> do
        modify (dynInsert t e)
        m