Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bringing where clause into scope in GHCi debugger

Earlier today, I was trying to debug a version of the below solve function that was giving me problems:

newtype Audience = Audience { byShyness :: [Int] }

solve :: Audience -> Int
solve (Audience originalCounts) = numFriendsAdded
  where numFriendsAdded = length $ filter id friendAdded
        friendAdded     = zipWith3 (\i c t -> i >= c + t) [0..] originalCounts alreadyStanding
        alreadyStanding = scanl (+) 0 modifiedCounts
        modifiedCounts  = zipWith (\a c -> if a then 1 else c) friendAdded originalCounts

In GHCi (7.8.2) I tried to break on solve by name, then by line/column, but it didn't seem to bring the names bound in the where clause into scope:

λ :b solve 
Breakpoint 0 activated at StandingOvation.hs:(20,1)-(24,89)
λ :main StandingOvation.example-input 
Case #1: Stopped at StandingOvation.hs:(20,1)-(24,89)
_result :: Int = _
λ numFriendsAdded
<interactive>:5:1: Not in scope: ‘numFriendsAdded’
λ :delete 0
λ :b 20 35
Breakpoint 1 activated at StandingOvation.hs:20:35-49
λ :main StandingOvation.example-input 
Case #1: Stopped at StandingOvation.hs:20:35-49
_result :: Int = _
numFriendsAdded :: Int = _
λ numFriendsAdded                                                                                                     
0
λ friendAdded
<interactive>:10:1: Not in scope: ‘friendAdded’

Obviously, they're in mutual scope as far as Haskell is concerned, but what do I need to do to make them visible when debugging?

like image 626
rampion Avatar asked Sep 28 '22 07:09

rampion


1 Answers

Unfortunately, the GHCi debugger does not make everything in scope available at a breakpoint. To quote from the user manual (text identical in 7.8.2 and 7.10.1 (latest)):

GHCi has provided bindings for the free variables[6] of the expression on which the breakpoint was placed (a, left, right), and additionally a binding for the result of the expression (_result). [...]

and the footnote:

[6] We originally provided bindings for all variables in scope, rather than just the free variables of the expression, but found that this affected performance considerably, hence the current restriction to just the free variables.

Essentially, you can only see local variables if they are mentioned directly in the expression GHCi is currently stopped at. Which makes me think of a workaround, which although pretty silly does work. Replace the main line of the function by:

solve (Audience originalCounts) =
    (friendAdded,alreadyStanding,modifiedCounts) `seq` numFriendsAdded

Now all the variables you're interested in are mentioned in the expression, so you can stop at it to see them all.

like image 114
Ørjan Johansen Avatar answered Oct 19 '22 23:10

Ørjan Johansen