haskellghcihaskell-warp

Using ghci debugger in a wai/warp app


Here's a trivial wai/warp program so I can learn how ghci debugger actually works:-

{-# LANGUAGE OverloadedStrings #-}
import Network.Wai
import Network.HTTP.Types (status200)
import Network.Wai.Handler.Warp (run)
import Debug.Trace (trace)

myApp req respond = do 
    let x = 1 {- line 8 -}
    putStrLn "processing request" {- line 9 -}
    putStrLn "Hoooray!" {- line 10 -}
    respond $ responseLBS status200 [("Content-Type", "text/plain")] "Hello World" 

main = run 3000 myApp 

In ghci, I first load this program (e.g. with :load hellowai.hs).

Then, I set my break points in line 9 and line 10 with

:break 9
:break 10

Then, in ghci, I execute main.

I then run localhost:3000 on my browser or with curl (doesn't matter of course) and my program breaks at line 9 as expected.

How do I print out (introspect) x and how do I introspect req ?

I tried using :print and ghci simply complains "Not in scope".

Stopped at hellowai.hs:9:5-33
_result :: IO () = _
[hellowai.hs:9:5-33] *Main> :print x

Top level: Not in scope: ‘x’
[hellowai.hs:9:5-33] *Main> :print req

Top level:
    Not in scope: ‘req’
    Perhaps you meant one of these:
      ‘rem’ (imported from Prelude), ‘seq’ (imported from Prelude)
[hellowai.hs:9:5-33] *Main>

Solution

  • With the GHCi command :print ... (or :sprint ...) you can print out the variables in scope. This however will print only evaluated values (recall Haskell is lazy).

    To evaluate and print, just use the name of the variables directly. You can get a list of the variables in scope with the :show bindings command.

    If you do not see the variables in scope, it is possible that they have been optimized away by the compilier. In your code, you do not use x, so that is likely removed during compilation. Also, code such as

    foo = do
      let x = 3
      print "aa"
      print "bb"
      print x
    

    is probably handled as (line numbers aside)

    foo = do
      print "aa"
      print "bb"
      let x = 3
      print x
    

    So you will not see x in scope until the last line. In such cases, use :step to advance your execution a little until you see x appear.