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!