我有一些使用ST单子进行评估的代码。我喜欢不在每个地方都放置IO,因为runST方法生成纯结果,并表明这种结果是安全的(与unsafePerformIO相比)。但是,随着我的一些代码变得越来越长,我确实想要添加调试打印语句。
是否有任何类提供双重性格的单子 [或类型类机制],可以根据其类型或“isDebug”标志而变成 ST 或 IO?我记得 SPJ 在他的“Fun with Type Functions”论文中介绍了一个“Mutation”类,它使用关联类型将 IO 与 IORef 相关联并将 ST 与 STRef 相关联。是否存在某个包中?
编辑/解决方案
非常感谢[C.A.McCann],使用该解决方案,我能够引入一个额外的类,用于支持pdebug函数的单子。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单子,因此您可以轻松调试它,然后在实际想要运行它时使用类似“testR”的东西来调用它。
seq (somecomp somedata) ()
;第一次它会打印调试信息和错误消息,第二次只有错误消息。当然,:r
可以解决问题,但我更希望它有更好的语义(即Debug.Trace有点像一个hack)。 - gatoatigrado