Hello fellow haskellers,
I am wondering if anyone has an idea whether I'd run into trouble if I
rebound >>= in order to provide a more restricted monad. My idea is to
define a class:
class WitnessMonad wm where
(>>=) :: wm w w' a -> (a -> wm w' w'' b) -> wm w w'' b
(>>) :: wm w w' a -> wm w' w'' b -> wm w w'' b
return :: a -> wm w w' a
fail :: String -> wm w w' a
which obviously just adds a couple of phantom types indicating the monad
state prior to and after each operation. I actually rather like this
redefined monad, as it seems like it'd be useful in lots of places (e.g. a
restricted IO monad that disallows use of a file handle after it's
closed).
It seems to me like this would be a pretty cool kind of monad. It'd allow
us to encode typechecked "properties" in a monad, and there'd be very
little restriction on how tricky those properties could be. And we'd get
this all using the same do syntax we all love (and the new properties are
by definition sequential, so a monad is precisely what we want, only at the
type level).
One trouble I see is how to move an ordinary monad into the WitnessMonad
class. Of course, they differ in kind, so we need to do something, but I'm
not sure what, and suspect that folks with experience using monad
transformers will immediately see the answer. Of course, I want to be able
to use both my fancy witnessed monad and IO in the same module, and I want
to be able to use do notation for both of them.
I suppose we could easily define
data M m w w' c = M (m c)
lift = M
lower (M m) = m
instance WitnessMonad (M m) where
f >>= g = lift $ Prelude.(>>=) (lower f) (lower . g)
...
but then we'd have to lift all our operations, so an ordinary IO function
in a module that used my fancy rebound do notation would look like
f :: IO Char
f = lower $ do lift $ putStr "Hello world"
lift $ getChar
which seems rather heavy. Can anyone think of syntax-light way to allow my
hypothesized rebound do-notation to also work with ordinary monads?
--
David Roundy
Department of Physics
Oregon State University