On 4/10/08, Adam Smyczek <[EMAIL PROTECTED]> 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 _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe