I was fascinated by this video on visualization of Haskell heap, but unfortunately I haven't been able to use ghc-vis. My understanding is that it is too old now. (Feel free to suggest how to actually compile it here if you think the tool is still usable on a modern install.)
Is there some other package that allows similar visualization, or at least a text-based inspection of the heap?
For instance, say I type the following in ghci
λ> data Person = Person { name :: String,
surname :: String,
age :: Int
} deriving Show
λ> baron = Person { name = "Cosimo",
surname = "Piovasco di Rondò",
age = 12 }
λ> oldBaron = baron { age = 65 }
λ> brother = baron { name = "Biagio" }
λ> baron
Person {name = "Cosimo", surname = "Piovasco di Rond\242", age = 12}
λ> oldBaron
Person {name = "Cosimo", surname = "Piovasco di Rond\242", age = 65}
λ> brother
Person {name = "Biagio", surname = "Piovasco di Rond\242", age = 12}
My understanding is that
baron is evaluated, most of the allocation happens;oldBaron is evaluated, only a bunch of pointers are created for the new structure to share everything with the previous one, baron, except for age, which requires allocating another Int;brother is evaluated, the same happens again, but this time the re-pointed pointer is name;os across the 3 Persons are all actually pointer pointing to the same, single instance of 'o', and similarly for the other letters.Is there a tool/package that can show me all of this?
I know that the :sprint command can help me visualize lazyiness, for instance, before evaluating the three names in the snipet above, I could do
λ> :sprint baron
baron = <Person> _ _ 12
λ> :sprint oldBaron
oldBaron = _
λ> :sprint brother
brother = _
and see that nothing has been computed yet; then, if I evaluate only brother, I can repeat the commands above and I'll get
λ> :sprint baron
baron = <Person> _ "Piovasco di Rondò" 12
λ> :sprint oldBaron
oldBaron = _
λ> :sprint brother
brother = <Person> "Biagio" "Piovasco di Rondò" 12
which does reveal something along the lines of what I'm asking, becuase it shows that surname brother points effectively to surname baron.
The svgcairo issue you linked to in your other comment has a link to a PR with the fix. It just hasn't been merged by the maintainer. The beauty of open source is that you can apply the fix for your own sake.
Here are the steps I took to get ghc-vis running with GHC 9.6 (and for completeness, I am on Ubuntu 24.04, there appears to be at least one additional fix to apply to work on MacOS).
Get svgcairo
git clone https://github.com/gtk2hs/svgcairo
Edit svgcairo.h to rename librsvg/librsvg-features.h to librsvg/rsvg-features.h
Edit svgcairo.cabal to remove the upper bound on Cabal
Get ghc-vis to install it together with the locally fixed svgcairo (maybe there is a more direct way to build ghc-vis while using a local svgcairo, but I don't know it):
git clone https://github.com/def-/ghc-vis
echo "packages: ghc-vis svgcairo" > cabal.project (from the directory containing both ghc-vis and svgcairo)
cabal install --env . --lib ghc-vis --with-compiler=ghc-9.6
Start ghc-vis (make sure to use the version of ghc(i) that matches the installation)
ghci-9.6
ghci> :script ghc-vis/ghci
ghci> :vis
# a window opens
Visualize a value:
ghci> let a = [1..3]
ghci> :view a
(At this point I ran into another error due to a missing dot command, which was fixed by apt install graphviz.)
The window now displays a graph:
Press v to switch to the "list view" (the colorful boxes in the ghc-vis user guide), and back to the graph view.
In the graph view, you can click AP and Thunk nodes to force evaluation.
In the list view, you can click t_ nodes to force evaluation.