Zach's Querying plists blog post showcases a neat little querying DSL for plists. I couldn't shake the feeling that it looked an awful lot like pattern matching. I've often been impressed by optima, but I barely get to use it, so I thought I should try and see what querying plists looked like using pattern matching.
Here's what I came up with. Zach's example
(query-plists '(:and (:= :first-name "Zach") (:= :state "ME") (:not (:= :last-name "Beane"))) *people*)
(remove-if-not (lambda-match ((plist :first-name "Zach" :state "ME" :last-name (not "Beane")) t)) *people*)
It turned out more succinct than I initially expected! Also, it's trivially adaptable to other kinds of objects. E.g., given the following class:
all we have to do is swap
(defclass person () ((first-name :initarg :first-name) (last-name :initarg :last-name) (state :initarg :state)))
plistwith the class name
personand we're all set:
(remove-if-not (lambda-match ((person :first-name "Zach" :state "ME" :last-name (not "Beane")) t)) *people*)
We can't quite define something exactly like Zach's
query-plistsbecause, AFAICT, optima's patterns are not first-class objects but perhaps we can cheat a little bit.
;; naming things is hard. :-/ (defmacro matchp (pattern) `(lambda-match (,pattern t))) (defun filter (predicate list) (remove-if-not predicate list)) (filter (matchp (plist :first-name "Zach" :state "ME" :last-name (not "Beane"))) *people*)
Making this equally succinct when the query criteria are not constant is a challenge for another day and makes it clear that
matchpis a lousy abstraction. ;-)