I never blog about Lisp. What I use for apropos

(update: several people have mentioned Edi Weitz’s excellent regex apropos. I think that the code below complements the regex approach but that’s mostly because I usually think in terms of “find me a symbol with this and that” rather than in terms of regular expressions).

Apropos is great but simple string matching isn’t enough. I don’t think I’ve blogged about this before (sorry if I have but googling site:www.metabang.com apropos didn’t find any results.

My aproposing code is below. It takes a list of string arguments (using &rest) and returns the symbols that contain every string passed in. If you don’t specify that package, it looks in all of them (like apropos). If you pass in an symbol that names a package, then the search is restricted to that package.

(defun ap (&rest args)
  (let ((package nil)
  (search-list nil))
    (loop for arg in args do
   (if (and (symbolp arg) (find-package arg))
       (setf package (find-package arg))
       (push arg search-list)))
    (%ap (nreverse search-list) package)))

(defgeneric %ap (thing &optional package))

(defmethod %ap ((thing string) &optional package)
  (let ((*package* (or (and package (find-package package))
    (apropos-list thing package)))

(defmethod %ap ((thing symbol) &optional package)
  (%ap (symbol-name thing) package))

(defmethod %ap ((thing list) &optional package)
  (cond ((null thing) nil)
  ((null (rest thing)) (%ap (first thing) package))
   (let ((current (%ap (first thing) package)))
     (dolist (next (rest thing))
       (setf current (intersection current (%ap next package))))

(export 'ap)


> (cl-user::ap "bind" "value")
(multiple-value-bind compiler::pa-multiple-value-bind

> (cl-user::ap "bind" "value" :cl-user)

It works for me! Suggestions, as always, welcome.