1

I am interested in extending pcase with patterns which:

  1. Complement an existing pattern, e.g. (not (pred string-empty-p)). Such a pattern would match where the non-negated form does not match and vice versa.
  2. Match when a predicate applied to the object being matched returns nil, e.g. (npred (string= "foo")).

The following is my first attempt at the former:

(pcase-defmacro not (pat)
  (let ((obj (make-symbol "obj")))
    `(and ,obj (guard (not (pcase ,obj (,pat)))))))

I would appreciate any suggestions for improvement of (1) (e.g. how to avoid a nested pcase) and implementation approaches for (2). Are there any conditions under which such patterns would be a bad idea (other than there being a better, non-pcase alternative)? Is there an idiomatic/elegant way of achieving the same effect which does not involve defining new pcase patterns?

Update

I think the pred pattern is constrained enough to allow for the following implementation for (2):

(eval-when-compile (require 'subr-x))

(pcase-defmacro npred (pat)
  (let ((obj (make-symbol "obj")))
    `(and ,obj (guard (not (thread-last ,obj ,pat))))))
phils
  • 48,657
  • 3
  • 76
  • 115
Basil
  • 12,019
  • 43
  • 69

1 Answers1

1

If you want to do it right, then you need to reimplement pcase following the design of Racket's match more closely. I didn't do that, because this generates code which uses local lambda definitions fairly extensively, which Elisp's compiler sadly handles rather poorly.

If you look at the end of pcase--u1 you'll see some left-over handling of such a not pattern, which used to work for some cases, along with a comment giving some vague explanation for possible way to improve it (but currently, this never works anyway).

Update

What will be Emacs 28 has gained support for a very limited subset of negation in the form of (pred (not FUN)). For example:

(pcase "foo" ((pred (not (string= "bar"))) 'yes)) ;; => yes
Stefan
  • 26,154
  • 3
  • 46
  • 84
  • Thank you for the interesting background and pointer; I intend to have a closer look when I find the time. – Basil May 23 '17 at 13:41