wind2412
wind2412

Reputation: 1069

Haskell - How to print some value in a function for debugging purpose?

I'm a Haskell newbie and I want to do something which has a side effect like this:

i = 3.0

main :: IO ()
main = let m = print i in putStrLn "Hello world"

Then I can know the value of i when main runs, but the I didn't print. I add ! before m but it also doesn't work. I would like to know how to hack this, thanks in advance!

Upvotes: 4

Views: 3603

Answers (3)

Jon Purdy
Jon Purdy

Reputation: 55069

In an IO action, you can just use putStrLn or print as usual, like

do
  print i
  putStrLn "Hello world"

Which desugars to print i >> putStrLn "…". This is equivalent, but not really any better because the action m doesn’t really need to be named:

let m = print i  -- define an action
in do
  m  -- ensure the action is actually executed
  putStrLn "Hello world"

In a pure function, you can use trace or traceShow from Debug.Trace:

traceShow i (putStrLn "Hello world")

But be aware that these print when the expression is forced, which may be in a different order than you may expect due to lazy evaluation, or not at all if a value is never used. You can add strictness annotations with seq or BangPatterns as you tried for the monadic code to assist with making sure that things are forced when you expect—the reason !m = … didn’t work for your IO action is that the strictness annotation only makes the expression evaluated, producing an IO action but not executing it because it’s not sequenced with another action as part of main. Remember: you can only (purely) construct IO actions and bind them together; the runtime is what actually executes them.

Finally, in a “pure” monad where you don’t have IO available, you can still use trace &c., for example in the list monad:

numbers :: [Int]
numbers = do
  x <- [1, 2, 3]
  traceShow x (pure ())
  y <- [4, 5, 6]
  traceShow y (pure ())
  pure (x * y)

Upvotes: 4

n. m. could be an AI
n. m. could be an AI

Reputation: 120079

For debugging, use trace and friends.

import Debug.Trace
i = 3.0

main :: IO ()
main = traceShow i $ putStrLn "Hello world"

See it live

Note the trace appears on the standard error stream, as debugging output should.

The function you use trace in doesn't have to be IO-typed. This for example will also work:

add a b = a + traceShow i b

Trace functions are a bit foreign to Haskell because they are technically impure. However the side effects are limited in scope and not observable by the program itself, so it's kinda OK.

More info

Upvotes: 5

talex
talex

Reputation: 20542

You created m but never used it. To fix that you can try:

i = 3.0

main :: IO ()
main = let m = print i in m >> putStrLn "Hello world"

Upvotes: 3

Related Questions