💾 Archived View for gem.librehacker.com › gemlog › starlog › 20240122-0.gmi captured on 2024-02-05 at 09:26:41. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
One of the most fun things about working with lisps is the (often) great support for introspection. That means looking inside objects, in real time, to find out what they are, what they are made of, and how they work.
In Common Lisp this is really fun, because the built-in inspector provides lots of information, and we also have Emacs SLIME, which makes inspection navigation as easy as a stroll in the garden. Included in that is the source code location and, if you dive deep enough down the tree, the underlying assembly code.
CL is my lisp of choice now, but lately I've been trying to become more intimate with Guix REPL, which is just a Guile REPL and a bunch of scheme modules. So I've been trying to figure out Guile introspection. The Guile REPL has a built-in introspection tool, but it usually doesn't show you much more than the type name of the object. But inspection procedures are available. This is from Guile version 3.0.9:
If you don't already know what exact procedures you are looking for, it is helpful to inspect modules. First, you need to get a module object. If you are already in the module of interest, you can run
scheme@(guix-user)> ,m guix scheme@(guix)> (current-module) $7 = #<directory (guix) 7fd5b92bfe60>
But it is more convenient usually to get the module from outside of it, using `resolve-module':
scheme@(guile-user)> (resolve-module '(guix)) $8 = #<directory (guix) 7fd15472f960>
To look over defined symbols in the module, there is `module-for-each', which iterates over each symbol/value pair. You can list out the symbol names with something like this:
(define (list-module-symbols module) (module-for-each (lambda (a b) (map display (list a "\n"))) module))
E.g.:
scheme@(guile-user)> (list-module-symbols (resolve-module '(guix packages))) lookup-package-propagated-input package-build-system package-location-vector origin-patch-flags transitive-inputs %content-hash?-procedure ...etc...
For procedures, you can (usually) get the location of the source code with `program-sources'. First you need to be able to get the procedure object, either from within the module, or from reaching into it with `@' or `@@'.
scheme@(guile-user)> ,use (system vm program) scheme@(guile-user)> (@@ (guix packages) package-build-system) $12 = #<procedure %package-build-system-procedure (s)> scheme@(guile-user)> (program-sources $12) $13 = ((0 "guix/packages.scm" 567 . 0))
Section 6.7.3 of the Guile manual describes the accessors:
-- Scheme Procedure: source:addr source
-- Scheme Procedure: source:line source
-- Scheme Procedure: source:column source
-- Scheme Procedure: source:file source
There can be more than one source datum, so you would need to use `car' to get the first one:
scheme@(guile-user)> (source:file (car (program-sources (@@ (guix packages) package-build-system)))) $15 = "guix/packages.scm"
Lunch break is over, so I'll have to end it here for today...