我有一些代码目前使用 ST monad 进行评估。我不喜欢将 IO 放在任何地方,因为该runST
方法会产生纯结果,并表明这样的结果可以安全调用(相对于unsafePerformIO
)。但是,由于我的一些代码变得更长,我确实想将调试打印语句放入其中。
是否有任何类提供双重人格 monad [或 typeclass 机器],可以是 ST 或 IO(取决于其类型或“isDebug”标志)?我记得 SPJ 在他的“Fun with Type Functions”论文中引入了一个“Mutation”类,它使用关联类型将 IO 与 IORef 和 ST 与 STRef 相关联。这样的东西在某处作为一个包存在吗?
编辑/解决方案
非常感谢 [第 n 次],CA McCann!pdebug
使用该解决方案,我能够为支持函数的 monad 引入一个附加类。monad将ST
忽略这些调用,而IO
将运行putStrLn
.
class DebugMonad m where
pdebug :: String -> m ()
instance DebugMonad (ST s) where
pdebug _ = return ()
instance DebugMonad IO where
pdebug = putStrLn
test initV = do
v <- newRef initV
modifyRef v (+1)
pdebug "debug"
readRef v
testR v = runST $ test v
这在 ghci 中有一个非常幸运的结果。由于默认情况下它期望表达式是 IO 类型,运行类似“test 3”的东西会导致 IO monad 被运行,所以你可以很容易地调试它,然后当你真正想要运行时用类似“testR”的东西调用它它。