Using GHC 9.6.2 and looking at the GHC Core output, I see a lot of
break<N>
, where N is a small integer. What does this mean?
For example, from a source definition:
type Store = Map Id Integer
impInitStore :: [Id] -> Store
impInitStore ids = fromList $ zip ids (repeat 0)
I generate the Core with:
stack runghc -- -O2 -fforce-recomp -ddump-simpl -dsuppress-all \
src/KImp.hs > tmp/ghccore2
and in the output I see:
impInitStore
= \ ids2_aZd ->
break<236>(ids2_aZd)
$ (fromList $dOrd_r2pw)
(break<235>(ids2_aZd) zip ids2_aZd (break<234>() repeat (IS 0#)))
These are breakpoints (for interactive debugging). break<N>
usually evaluates like the identity function (break<N>(...) x = x
) but, if it is evaluated while "active", it instead suspends evaluation and yields to the debugger. The N
is a unique identifier which allows the debugger to selectively activate and deactivate breakpoints. GHC does not support "inserting" breakpoints into already loaded code, but rather bakes all possible breakpoints into code as it is loaded and simply flags them all as inactive until the user requests otherwise. (See also: this fun corner case where you can observe inactive breakpoints.)
Note that the N
identifiers are not meant to be user facing. To identify a "precise" breakpoint to GHCi, you would specify the breakpoint by its line and column. The contents of the (...)
in a break<N>(...)
is a list of names whose values will be printed out by the debugger when the breakpoint is hit. So, for example, if I load your code and activate the middle breakpoint...
$ ghci -ddump-simpl -dsuppress-all Code.hs
# ...
impInitStore
= \ ids_aNR ->
break<2>(ids_aNR)
$ (fromList $fOrdInteger)
(break<1>(ids_aNR) zip ids_aNR (break<0>() repeat (IS 0#)))
> :break Code 7 37
# "break on entering the subexpression containing Code.hs line 7 column 37"
Breakpoint 0 activated at Code.hs:7:31-48
# note that the span of the breakpoint corresponds to the expression governed by the break<1>
# the internal breakpoint ID 1 is not exposed (GHCi just counts activated breakpoints starting from 0)
...then triggering the breakpoint will "focus" the subexpression zip ids (repeat 0)
and print out the variable ids
.
ghci> impInitStore [1, 2]
# ...
fromList Stopped in Code.impInitStore, Code.hs:7:31-48
_result :: [(Id, Integer)] = _
ids :: [Id] = [1,2]
[Code.hs:7:31-48] ghci> :list
6 impInitStore :: [Id] -> Store
7 impInitStore ids = fromList $ zip ids (repeat 0)
8
Ordinary compiled code does not contain breakpoints, but runghc
runs code via the interpreter, instead of compiling it. Hence the code picks up breakpoints. (For the same reason, I don't believe -O2
does anything when using runghc
.) (I would think it is a pessimization to have breakpoints in runghc
. Try -fno-break-points
to turn them off.)