1
votes

While using The Glorious Glasgow Haskell Compilation System, version 8.0.2, I'm trying to add trace information to the following script:

import Debug.Trace
init :: Show a => [a] -> [a]
init l@(x:xs) | trace
          (
            if (length l) < 2
               then ( "\n\tinit [" ++ show x ++ "] = []" )
               else ( "\n\tinit " ++ show l ++ " = " ++ show x ++ " : (init " ++ show xs ++ ")" )
          ) False = undefined
init [_] = []
init (x:xs) = x : (Main.init xs)

However, the output of the trace is interleaved with the output of evaluating the expression Main.init [2,3,5,7], as shown below:

C:\>ghci my_script.hs
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( my_script.hs, interpreted )
Ok, modules loaded: Main.
*Main> Main.init [2,3,5,7]

        init [2,3,5,7] = 2 : (init [3,5,7])
[2
        init [3,5,7] = 3 : (init [5,7])
,3
        init [5,7] = 5 : (init [7])
,5
        init [7] = []
]
*Main> :quit
Leaving GHCi.

How would one cause the following four lines to be omitted from the output?

[2
,3
,5
]

I have already tried using a couple of different variations of :set -fno-print-bind-result as shown at https://downloads.haskell.org/~ghc/6.8.1/docs/html/users_guide/interactive-evaluation.html, but to no avail.

2
Please don't edit answers into questions. If you have something to add to the existing answers, leave a comment to them or, if it is a different solution altogether, post it as a new answer (it is fine to answer your own questions). I have rolled back your edits -- here is a link to the source, in case you want to use them for something else.duplode

2 Answers

1
votes

GHCi implicitly uses print, and being lazy, it prints elements of a list as it evaluates them. You can compose it with a function that forces the whole list first.

force :: [a] -> [a]
force xs = go xs `seq` xs
  where go [] = ()
        go (x : xs) = x `seq` go xs

In ghci:

> print . force $ init [2, 3, 5, 7]

force also exists in a more general form in the deepseq library, and with it you can use -interactive-print to set print . force to be the default printer.

1
votes

Well the reason those lines are interleaved is because the list is the actual return value of your Main.init function. To be able to see the trace you need to force execution of the Main.init function. You could do this by enforcing strictness (seq, deepseq), but I think the simplest way would be to simply use the result in a way that doesn't interleave intermediate results.

If you just want the trace without interleaved data but you don't care about data at the end, how about using sum to use the list.

I suggest you try in ghci:

λ > sum (Main.init [2,3,5,7])

    init [2,3,5,7] = 2 : (init [3,5,7])

    init [3,5,7] = 3 : (init [5,7])

    init [5,7] = 5 : (init [7])

    init [7] = []
10

Other method:

Since trace outputs to stderr and not stdout you can split the output on the command line:

➜  ~ ghc temp.hs -e "Main.init [2, 3, 5, 7]" > /dev/null

    init [2,3,5,7] = 2 : (init [3,5,7])

    init [3,5,7] = 3 : (init [5,7])

    init [5,7] = 5 : (init [7])

    init [7] = []