划分IO monad

时间:2013-12-02 00:14:18

标签: haskell io monads

很高兴知道(至少在Safe Haskell中)来自签名是否某些东西执行IO操作,但IO包含许多不同的东西 - putStr,数据库访问,删除和写入文件, IORefs等

如果我在运行任意代码时使用类型签名作为安全措施,那么我可能会愿意接受一些IO操作 - 例如putStr之类的 - 但不是其他。

有没有办法定义IO monad的受限版本,只有一部分正常的IO操作?如果是这样,一个例子(例如putStr)将非常受欢迎!

2 个答案:

答案 0 :(得分:24)

作为我评论的后续内容,您可以使用

之类的内容自行实现
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

这绝对没有运行时开销,因为GHC会优化那些类型类只使用IO monad,它是可扩展的,易于编写,并且可以与monad变换和MonadIO结合使用上课很容易。如果您有多个类,例如定义了StdingetLine_等的getChar_类,您甚至可以将这些类型类与

组合在一起
class (Stdout io, Stdin io) => StdOutIn io where

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

main :: IO ()
main = myFunc

答案 1 :(得分:10)

只需使用Monad实例定义newtype IO a周围,定义预先批准的函数的包装版本,不导出构造函数,以便仅你包装的函数可以在monad中使用。