Delimiting the IO monad

haskell, io, monads

Solution

As a follow up to my comment, you can implement it yourself with something like

class Monad io => Stdout io where
    putStr_ :: String -> io ()
    putStrLn_ :: String -> io ()
    print_ :: Show a => a -> io ()
    -- etc

instance Stdout IO where
    putStr_ = putStr
    putStrLn_ putStrLn
    print_ = print

myFunc :: Stdout io => io ()
myFunc = do
    val <- someAction
    print_ val
    let newVal = doSomething val
    print_ newVal

main :: IO ()
main = myFunc

This will have absolutely no runtime overhead, since GHC will optimize away those typeclasses to use only the `IO` monad, it's extensible, easy to write, and can be combined with monad transformes and the `MonadIO` class quite easily. If you have multiple class, such as a `Stdin` class with `getLine_`, `getChar_`, etc defined, you can even combine these typeclasses with

class (Stdout io, Stdin io) => StdOutIn io where

myFunc :: StdOutIn io => io ()
myFunc = do
    val <- getLine_
    putStrLn_ $ "Echo: " ++ val

main :: IO ()
main = myFunc

Problem

It's nice to know (in Safe Haskell, at least) from the signature whether or not something performs IO actions, but IO encompasses a lot of different things - `putStr`, database access, removing and writing to files, IORefs, etc. If I'm using the type signatures as a security measure when running arbitrary code, it might be the case that I'm willing to accept some IO actions - `putStr` and the ilk, for instance - but not others. Is there a way to define a restricted version of the IO monad, with only a subset of the normal IO actions? If so, an example (with `putStr`, for instance) would be very welcome!

Original source