[Haskell-cafe] Fighting the monad stack, MonadIO
Ryan Ingram
ryani.spam at gmail.com
Thu Apr 10 21:06:18 EDT 2008
On 4/10/08, Adam Smyczek <adam.smyczek at gmail.com> wrote:
> If yes, is this a general concept/pattern
> how to hide functionality of a underlying monad,
> in this case hide IO entirely?
Yes, that's correct, although with IO you can't hide it entirely;
eventually you need a way to actually run the computation, and if
that's built on IO there's no way to do that without at least a way to
get -back- to the IO Monad.
On the other hand, you can use this to encapsulate "sandboxed" computations:
> module Console (Console, execConsole, consoleGetLine, consolePutLine)
> where
> newtype Console a = MkConsole { execConsole :: IO a }
> deriving (Monad, Functor)
> consoleGetLine :: Console String
> consoleGetLine = MkConsole getLine
> consolePutLine :: String -> Console ()
> consolePutLine = MkConsole . putStrLn
MkConsole is a private constructor not exported from this module, so
the only way to construct one is via the operations we provide and the
monad/functor operations. So we can prove that these operations never
do any network access, or file I/O, or weird pointer access.
Of course, with unsafeCoerce# and/or unsafePerformIO, client code can
break either/both of these claims:
> runConsole :: Console a -> a
> runConsole = unsafePerformIO . execConsole
> instance MonadIO Console where
> liftIO = unsafeCoerce#
> -- works because newtype is guaranteed not to change
> -- the runtime representation
-- ryan
More information about the Haskell-Cafe
mailing list