From: Stanisław Halik
Subject: [ANN] Toadstool, a pattern matching library for Common Lisp
Date: 
Message-ID: <gmr41v$2iva$1@opal.icpnet.pl>
Toadstool 0.1 has been released. It's a public domain pattern matching
library for CL <http://tehran.lain.pl/stuff/toadstool-0.1.tar>.

While it offers much of the functionality of Qi's matcher, there are
many more features thanks to a protracted development cycle.

All of built-in matching operators are written using a core protocol.
Additional operators can easily be written.

While I started it mainly to prove a point, hopefully to make a certain
frog shut up and stop spouting inane drivel about CL's "weaknesses",
it's actually pretty useful to avoid writing too many cadars.

It's an initial release, so much remains to discussion. The user
protocol is based on that of Qi, but it provoked responses about its
un-Lispiness. Parts of the developer interface seem unpolished as well.
If you have improvements or bugfixes in mind, please use email or the
thread for contact purposes.

From: budden
Subject: Re: Toadstool, a pattern matching library for Common Lisp
Date: 
Message-ID: <e56fb489-3a7c-4252-b4a5-f9d67690b788@h5g2000yqh.googlegroups.com>
1.
(toad-case (cons 42 69)
  (cons a a) -> :same
  (cons a b) -> :different
  t          -> :not-a-cons)

Yeah, this is really unlispy and I say definitely this is a bad
design. There is a way to macroexpand to entire
toad-case form:

(let ((clause1 '((cons a a) -> :same))
      (clause2 '((cons a b) -> :different)))
  `(toad-case (cons 42 69) ,@clause1 ,@clause2))

But I see no way to macroexpand to a separate clause.
E.g. in iterate, you write

(in-package :iterate)
(macrolet ((for-j-from-1-to-10 () `(for j from 1 to 10)))
              (iter (for-j-from-1-to-10) (collect j)))

And that's lispy. Loop is not lispy and you can't do so.

toad-case is not lispy too and you can't do that too.

Refer to iterate implementation (it uses codewalking for expanding
for-j-from-1-to-10).

So, now, if you wanted to prove CL power, you've done this wrong way.
You've made
lisp weaker within your particular library and this might be harmful
for CL.

2. Think about expressing patterns via backquote
(toad-case (cons 42 69)
  (`(,a ,@a) :same)) ...)
Fine for complex patterns. This is more to style than to pattern-
matching
implementation itself. But it needs cross-implementation testing due
to bacquoting
ambiguities (might smash static data sometimes). So it looks like
there are some limits of
this approach and it'd be find to make boundaries delimited.
I'd implemented my own portable backquoting (maybe with other macro-
characters) with cleaner semantics than that of
CL's backquote. It can base on cltl2 code. It is a separate task
though, but it looks like to be a fix to CL which would be
really useful. I've started that, but too many people here curse me so
I'm discouraged to continue this work.

3. Lisp is not new. Make sure to check prior art. There is at least
one sample pattern matching code in a books
and at least two pattern-matching libraries at lisp-related sites. If
you suffer from NIH syndrom, you should at least make better library
than anything that was done before. I'm using modified code stolen
from abclr(2) for myself, but this seems to be illegal so if I'll
publish my code, I'll need to make a change first.
From: Stanisław Halik
Subject: Re: Toadstool, a pattern matching library for Common Lisp
Date: 
Message-ID: <gmruf8$gbd$1@opal.icpnet.pl>
thus spoke budden <···········@mail.ru>:

> E.g. in iterate, you write

> (in-package :iterate)
> (macrolet ((for-j-from-1-to-10 () `(for j from 1 to 10)))
>              (iter (for-j-from-1-to-10) (collect j)))

> And that's lispy. Loop is not lispy and you can't do so.

In Toadstool, patterns occupy a separate namespace and usual macroexpand
won't do. There are naming conflicts. There could be toad-macrolet
functionality if that makes the matcher any better. In fact, it can be
written using the public protocol without poking at the innards :-) Here
it goes:

-->--
;; fix for a silly bug that broke anonymous classes
(defmethod toadstool-system::%components ((c standard-class))
  (list c))

(defpackage #:toad-macrolet
    (:use #:cl #:toadstool-system)
  (:export #:toad-macrolet))

(in-package #:toad-macrolet)

(defclass macrolet-form (operator)
  ((name :initarg name :reader name-of :allocation :class)
   (function :initarg function :reader function-of :allocation :class)
   (expansion :initarg form :reader expansion-of)))

(defun make-macrolet-class (name function)
  (let* ((m-f (find-class 'macrolet-form))
         (class (make-instance 'standard-class :direct-superclasses
         `(,m-f))))
    (closer-mop:finalize-inheritance class)
    (reinitialize-instance (closer-mop:class-prototype class)
                           'function function
                           'name name)
    class))

(defmethod initialize-instance :after ((c macrolet-form) &key)
  (setf (slot-value c 'expansion)
        (mkform (apply (function-of c)
                       (cdr (form-of c))))))

(defmethod expand-form ((c macrolet-form) expr k)
  (expand-form (expansion-of c) expr k))

(defmacro toad-macrolet (&environment env bindings &body body)
  (let* ((macros (loop for (name lambda-list . body) in bindings
                      collect (make-macrolet-class name
                                   (compile nil `(lambda ,lambda-list .
                                   ,body)))))
         (*used-components* (append macros *used-components*)))
    (cl-walker:macroexpand-all `(progn . ,body) env)))
--<--

And an example:

  (toad-macrolet ((foo (&rest args) 
                    `(list . ,args)))
    (toad-case '(1 2 3)
      (foo a b c) -> (values a b c)))

I'm not particularly proud of forced macroexpansion but there seems to
be no better way to communicate a special binding at compile time.

> 3. Lisp is not new. Make sure to check prior art. There is at least
> one sample pattern matching code in a books
> and at least two pattern-matching libraries at lisp-related sites.

By the time I found out about Fare's matcher I was already writing my
code. But yes, it was written largely for NIH value :-)
From: budden
Subject: Re: Toadstool, a pattern matching library for Common Lisp
Date: 
Message-ID: <5d52b9d6-ac57-4e2f-9598-af9419ac0ac2@s20g2000yqh.googlegroups.com>
Ok, special macroexpansions are approprite sometimes, but there are
still other (simpler) ways
to use macros if syntax was lispy.