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))
           *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))
  (t
   (let ((current (%ap (first thing) package)))
     (dolist (next (rest thing))
       (setf current (intersection current (%ap next package))))
     current))))

(export 'ap)

Examples:

> (cl-user::ap "bind" "value")
(multiple-value-bind compiler::pa-multiple-value-bind
    excl::walk-multiple-value-bind
  excl::bindstack-value-prev
  excl::bindstack-value
  *bind-treat-values-as-values*
  bind-missing-value-form-warning
  sparql.executor::binding-values)

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

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

missile gap, salt mine gap, education gap…

There’s always a gap. I think that this one, however, is real.

The Future of Manufacturing, GM, and American Workers (Part II) | Robert Reich’s Blog

“But we’re in danger of losing ground because too many of our kids, especially those from lower-middle class and poor families, can’t get the foundational education they need. The consequence is a yawning gap in income and wealth which continues to widen. More and more of our working people finds themselves in the local service economy — in hotels, hospitals, restaurant chains, and big-box retailers — earning low wages with little or no benefits. Unions could help raise their wages by giving them more bargaining leverage. A higher minimum wage and larger Earned Income Tax Credit could help as well. “

announce: metabang-bind 0.7.4

I discovered a nasty bug in metabang-bind today caused by a gensym being created too early (i.e., it was created when I defined a macro rather than when a bind form in user-code was expanded.) Version 0.7.4 corrects this and adds a nifty new binding form: :structure/rw. This latter lets you both read and write to structure slots within the scope of a binding. Handy!

announce: tinaa 0.5.10

Firstly, my thanks to Frank Schorr for providing a very easy to follow test case. It turns out that:

  1. Tinaa still confused by iterators when [asdf-system-connections][asd] wasn’t loaded (because this meant that dynamic-classes didn’t get loaded…)

  2. Tinaa got very confused if a class had superclasses that weren’t defined (which is arguably understandable since those classes can’t be instantiated and therefore cannot be introspected… On the other hand, going into an infinite loop is generally not the best way to report an error!).

Thus I can announce Tinaa 0.5.10.

Enjoy.

announce: cl-markdown 0.10.5 and cl-containers 0.11.5

Shocking as it is, I’m actually posting an entry categorized with “lisp”. What is the world a’coming to.

Seriously, though, Tiarnan O’Corrain and Timothy Ritchey, reported a very basic problem with cl-markdown (i.e., it didn’t work). To put it simply, cl-markdown required asdf-system-connections but didn’t make this requirement explicit. ASC shouldn’t really be necessary so 0.10.5 (and cl-containers 0.11.5) add some more duct tape (chewing gum, bailing wire) to the mix in the hopes of getting things more or less straightened.

My apologies for the snafu. Let me know if things are still aft agley.

announce: lift 1.7.0

I’ve just bumped LIFT to 1.7.0. The minor version increment stems from a change made to ensure-cases. Previously, singleton variables required an extra layer of parentheses, like:

(ensure-cases (var)
  ((1) (2) (3))
  (ensure (numberp var)))

This was silly so I’ve restructured the macro so that you now only need say:

(ensure-cases (var)
  (1 2 3)
  (ensure (numberp var)))

On the negative side, this is an incompatible change. If you’re using ensure-cases, you’ll need to modify your tests. I think it’s better in the long run.

This version also includes several other minor bug fixes and improvements in how the pathname of a test report is computed. Enjoy.

announce: clnuplot 0.2.2

David Thompson submitted a patch that lets clnuplot handle X-axis labels. This turns this:

(in-package #:clnuplot)

(write-plot
 (clnuplot:make-plot
  :bar
  '((1 2 "a") (2 2.5 "b") (3 3.1 "c"))
  :linewidth 3.0
  :key "off"
  :filename "bar12"
  :xlabel "Bin Number"
  :ylabel "Dance Partners"
  :x-coord #'first
  :y-coord #'second
  :title "Bin Number versus Dance Partners"
  :ymin 0.0) :postscript)

into this:

bar12.png

Thanks.

(and thanks also to the word “this,” a tireless contributor to sentences everywhere.)