在Safe Haskell中,至少从函数签名中可以知道某个函数是否执行IO操作,但是IO包括很多不同的东西——putStr
、数据库访问、文件读写、IORefs等。
如果我将类型签名用作运行任意代码的安全措施,那么也许我愿意接受一些IO操作——例如putStr
等,但是不愿意接受其他操作。
是否有一种方法可以定义一个受限制的IO单子,只能执行一小部分正常的IO操作?如果可以的话,举个例子(例如使用putStr
)将非常受欢迎!
在Safe Haskell中,至少从函数签名中可以知道某个函数是否执行IO操作,但是IO包括很多不同的东西——putStr
、数据库访问、文件读写、IORefs等。
如果我将类型签名用作运行任意代码的安全措施,那么也许我愿意接受一些IO操作——例如putStr
等,但是不愿意接受其他操作。
是否有一种方法可以定义一个受限制的IO单子,只能执行一小部分正常的IO操作?如果可以的话,举个例子(例如使用putStr
)将非常受欢迎!
跟进我的评论,你可以使用类似的方法自己实现:
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 将优化这些 typeclasses 仅使用 IO
monad,它是可扩展的,易于编写,并且可以轻松地与 monad 转换和 MonadIO
类相结合。如果您有多个类,例如具有定义了 getLine_
、getChar_
等的 Stdin
类,您甚至可以将这些 typeclasses 结合起来。
class (Stdout io, Stdin io) => StdOutIn io where
myFunc :: StdOutIn io => io ()
myFunc = do
val <- getLine_
putStrLn_ $ "Echo: " ++ val
main :: IO ()
main = myFunc
Stdout
(标准输出),文件访问,网络,导弹发射等任何内容,然后任意、流畅地组合它们。 - daniel gratzertype StdOutIn io = (Stdout io, Stdin io)
以实现类似的效果。 - Alex Rconstraints
包。 - Alex R只需定义一个围绕IO a
的新类型,并使用Monad实例定义预批准函数的封装版本,不要导出构造函数,以便仅可以在monad中使用您封装的函数。