Typesafe MRef with a regular monad

oleg@pobox.com oleg@pobox.com
Tue, 10 Jun 2003 11:44:45 -0700 (PDT)


> update  :: (Typable b) => FM k -> Key k a -> b -> (FM ...)

I didn't know constraints on values are allowed... Given below is the
implementation of the required interface, in Haskell98

   module TypedFM where
        data FM k     -- Abstract; finite map indexed bykeys of type k
        data Key k a  -- Abstract; a key of type k, indexing a value of type a
 
        empty :: FM k
        insert :: Ord k => FM k -> k -> a -> (FM k, Key k a)
        lookup :: Ord k => FM k -> Key k a -> Maybe a
        update :: Ord k => FM k -> Key k a -> a -> FM k


Implementation:

import Monad

data U =  LBool Bool 
        | LChar Char
	| LInt Int
	| LL [U]  -- Lists of any kind
	| LA (U->U) -- monomorophic functions of any kind


class UNIV a where
    inj:: a -> U
    prj:: U -> Maybe a
    

instance UNIV Bool where
    inj = LBool
    prj (LBool a) = Just a
    prj _         = Nothing
    
instance UNIV Char where
    inj = LChar
    prj (LChar a) = Just a
    prj _         = Nothing

instance UNIV Int where
    inj = LInt
    prj (LInt a) = Just a
    prj _         = Nothing
    
instance (UNIV a) => UNIV [a] where
    inj = LL . map inj
    prj (LL as) = foldr f (Just []) as
        where f e (Just s) = case prj e of
	                     Just x -> Just $ x:s
			     _      -> Nothing
	      f _ _ = Nothing
    prj _         = Nothing

instance (UNIV a,UNIV b) => UNIV (a->b) where
    inj f = LA $ \ua -> let (Just x) = prj ua in inj $ f x
    prj (LA f) = Just $ \x -> let Just y = prj$f$inj x in y
    prj _         = Nothing

data FM k = FM [U]

data Key k a = Key Int a

empty = FM []

insert (FM l) _ a = (FM $(inj a):l, Key (length l) a)

lookp:: (UNIV a) => FM k -> Key k a -> Maybe a
lookp (FM l) (Key i a) = prj $ (reverse l)!!i

update:: (UNIV a) => FM k -> Key k a -> a -> FM k
update (FM l) (Key i _) a = FM $ reverse (lb ++ ((inj a):(tail lafter)))
    where (lb,lafter) = splitAt i (reverse l)

	  
test1 = do
	let heap = empty
	let (heap1,xref) = insert heap () 'a'
  	let (heap2,yref) = insert heap1 () [(1::Int),2,3]
  	let (heap3,zref) = insert heap2 () "abcd"
 	putStrLn "\nAfter allocations"
-- 	print heap3

 	putStr "x is "; print $ lookp heap3 xref
 	putStr "y is "; print $ lookp heap3 yref
 	putStr "z is "; print $ lookp heap3 zref
	
 	let heap31 = update heap3  xref 'z'
 	let heap32 = update heap31 yref []
 	let heap33 = update heap32 zref "new string"
 	putStrLn "\nAfter updates"

 	putStr "x is "; print $ lookp heap33 xref
 	putStr "y is "; print $ lookp heap33 yref
 	putStr "z is "; print $ lookp heap33 zref

 	putStrLn "\nFunctional values"
 	let (heap4,gref) = insert heap33 () (\x->x+(1::Int))
 	putStr "g 1 is "; print $ liftM2 ($) (lookp heap4 gref) $ Just (1::Int)
	return ()