On Wed, 04 Jun 2003 15:19:53 -0700 Ashley Yakeley <ashley@semantic.org> wrote:
In article <200306042005.h54K5mG0014203@adric.fnmoc.navy.mil>, oleg@pobox.com wrote:
Ashley Yakeley wrote: ] ] Is it possible to actually implement a working instance of RefMonad in ] ] Haskell, without making use of a built-in monad like IO or ST?
] You certainly wouldn't be able to do this for any monad M which had:
] performM :: forall a. M a -> a;
] ...because it wouldn't be type-safe: you'd be able to construct coerce ] :: a -> b just as you can with unsafePerformIO.
Fortunately, that doesn't seem to be the case.
That's only because you've failed to do the difficult part: implement newRef. Your monadic solution has a statically typed/sized store: I'd say it doesn't properly count as a "heap" since you can't heap new stuff on it.
I agree, if I knew I'd have 5 components before I could just use a 5 tuple and a State monad. I'd have to look back over the other heap stuff to see what it provides type-wise, but (at least the "new" monad version) seems to miss the point.
The original problem was to create an instance of
class Monad m => RefMonad m r | m -> r where newRef :: a -> m (r a) readRef :: r a -> m a writeRef :: r a -> a -> m ()
without making use of IO or ST. Given some M and R that have
instance RefMonad M R performM :: forall a. M a -> a
M = (forall s.ST s) R = STRef s e.g. runST :: (forall s.ST s a) -> a you can use the same trick for your own RefMonad. I'm not sure if this will work with RefMonad exactly. If ST/STRef can be made an instance of RefMonad without any trouble though, then I believe it should work.
one can write this:
coerce :: forall a b. a -> b; coerce a = let { ref = performM (newRef Nothing); } in performM (do { writeRef ref (Just a); mb <- readRef ref; case mb of {Just b -> return b;}; });
I was having fun with coerce :: a -> b coerce x = unsafePerformIO (writeIORef ref x >> readIORef ref) where ref = unsafePerformIO (newIORef undefined) last night, some fun examples (using GHCi 5.04.3), data Foo a = Bar | Baz a (Foo a) coerce 5 :: Maybe Int ==> Nothing coerce 'a' :: Int ==> 97 coerce [1..3] :: Foo Integer ==> (Baz 1 (Baz 2 (Baz 3 Bar))) coerce [4] :: Maybe Integer ==> Just 4 I need to reread the GHC internals paper, I want to see if I can get one like (coerce something :: (sometype -> someothertype)) someotherthing