4

出于调试目的,我们如何打印当前状态值?例如,在 http://www.haskell.org/haskellwiki/State_Monad的具体示例 1 的代码中,我们如何在读取每个输入字符后打印当前状态值?

module StateGame where

import Control.Monad.State

type GameValue = Int
type GameState = (Bool, Int)

playGame :: String -> State GameState GameValue
playGame []     = do
    (_, score) <- get
    return score

playGame (x:xs) = do
    (on, score) <- get
    case x of
       'a' | on -> put (on, score + 1)
       'b' | on -> put (on, score - 1)
       'c'      -> put (not on, score)
       _        -> put (on, score)
    playGame xs

startState = (False, 0)

main = print $ evalState (playGame "abcaaacbbcabbab") startState
4

2 回答 2

7

要进行快速而肮脏的调试,请使用tracefrom Debug.Trace。我经常发现翻转参数顺序并定义它很有用

infixl 0 `debug`

debug :: a -> String -> a
debug = flip trace

然后您可以将调试添加到行尾,并且更容易注释掉(并在最后删除)。

对于更有原则的日志记录,将StateaWritertell日志消息结合起来,或者StateT s IO如果您直接想要记录到文件或标准错误,请使用。

于 2012-01-25T12:23:08.033 回答
2

正如 nm 指出的那样Debug.Trace,但是自己编写一些东西很容易。但是,我强烈建议仅将其用于调试,并将其删除以用于真实世界的代码。这是一个例子:

import System.IO.Unsafe

output a b = seq (unsafePerformIO (print a))  b

(output "test" 23) * 25
-- "test"
-- 527

这里output需要一个要打印的参数和一个返回值,其行为类似于 a const,只是有一个副作用。seq需要强制评估print,否则懒惰会阻止打印任何内容。

于 2012-01-25T12:24:01.310 回答