我是Haskell新手,我想做一些有副作用的事情:
i = 3.0
main :: IO ()
main = let m = print i in putStrLn "Hello world"
然后我知道i
运行时main
的值,但是I
没有打印。我在!
之前添加了m
,但是它也不起作用。我想知道如何破解这个,谢谢!!
答案 0 :(得分:4)
要进行调试,请使用trace
和朋友。
import Debug.Trace
i = 3.0
main :: IO ()
main = traceShow i $ putStrLn "Hello world"
请注意,跟踪显示在标准 error 流中,就像调试输出一样。
您使用的trace
函数不必是IO类型的。例如,这也将起作用:
add a b = a + traceShow i b
跟踪功能对于Haskell有点陌生,因为它们在技术上不纯。但是,副作用的范围是有限的,并且程序本身无法观察到,因此还可以。
答案 1 :(得分:3)
您创建了m
,但从未使用过。要解决该问题,您可以尝试:
i = 3.0
main :: IO ()
main = let m = print i in m >> putStrLn "Hello world"
答案 2 :(得分:3)
在IO
操作中,您可以像平常一样仅使用putStrLn
或print
,例如
do
print i
putStrLn "Hello world"
对print i >> putStrLn "…"
不满意。这是等效的,但实际上并没有更好,因为实际上不需要命名操作m
:
let m = print i -- define an action
in do
m -- ensure the action is actually executed
putStrLn "Hello world"
在纯函数中,可以使用trace
中的traceShow
或Debug.Trace
:
traceShow i (putStrLn "Hello world")
但是请注意,这些表达式会在表达式受强制时打印,由于懒惰的求值结果,其顺序可能与您期望的顺序不同,或者,如果从不使用值,则根本不会打印。您可以在尝试单子代码时使用seq
或BangPatterns
添加严格性注释,以帮助确保在您期望的情况下强制执行操作– !m = …
对您的工作不起作用的原因IO
动作是严格注解仅使表达式 evaluated ,产生IO
动作,但不 execute 动作,因为它没有与其他动作进行排序作为main
的一部分。请记住:您只能(完全)构造 IO
动作并将其绑定在一起。运行时才是真正执行它们的地方。
最后,在没有IO
可用的“纯”单子目录中,您仍然可以使用trace
&c。,例如在monad列表中:
numbers :: [Int]
numbers = do
x <- [1, 2, 3]
traceShow x (pure ())
y <- [4, 5, 6]
traceShow y (pure ())
pure (x * y)