<nallen05@gmail.com> wrote:
+---------------
| Barry Margolin <bar...@alum.mit.edu> wrote:
| > r...@rpw3.org (Rob Warnock) wrote:
...
| > > > (mapcar #$(> $1 $2) '(1 2 3 4 5) '(5 4 3 2 1))
| >
| > > (NIL NIL NIL T T)
| > > > ...
...
| > > But I use this *only* at the REPL when poking around,
| > > *never* in saved source files...
| >
| > One problem I can see with this is that they don't nest properly. The
| > outer one will drill into inner one and see its implicit lambda
| > variables, and make them into lambda varables for the outer one.
+---------------
Mine doesn't "drill" at all, it just uses normal lexical scope
with a bunch of fixed pre-chosen optional lambda varables:
;;; SET-SHARP-DOLLAR-READER -- Experimental LAMBDA abbreviation (#1 of 2).
;;; SYNTAX: #$FORM
;;; An abbreviation of: (lambda (&optional $1 $2 $3 $4 $5 $6 $7 $8 $9 &rest $*)
;;; FORM)
;;; Within the FORM, args $1 ... $9 and $* are be lambda-bound as positional
;;; and &REST parameters, respectively. Usually, but not always, FORM will be
;;; an S-expr, e.g. #$(car $3), but this is legal: #$FOO ==> (lambda () FOO),
;;; that is, (CONSTANTLY FOO). Likewise, #$$3 ==> #'THIRD.
;;;
;;; As a convenience for interactive use, in the special case that FORM is a
;;; list and (car FORM) is also a list, then an implicit PROGN is provided,
;;; e.g., #$((foo) (bar)) ==> (lambda (args...) (foo) (bar)).
;;;
(defun set-sharp-dollar-reader ()
(flet ((sharp-dollar-reader (s c p)
(declare (ignore c p))
(let* ((form (read s t nil t)))
`(lambda (&optional $1 $2 $3 $4 $5 $6 $7 $8 $9 &rest $*)
(declare (ignorable $1 $2 $3 $4 $5 $6 $7 $8 $9 $*))
,@(if (and (consp form) (consp (car form)))
form
(list form))))))
(set-dispatch-macro-character #\# #\$ #'sharp-dollar-reader)))
So, yes, it suffers from variable capture.
But who cares? I've *never* found a use for nesting them.
As I said, "I use this *only* at the REPL when poking around..."
By the way, here's another style I've tried occasionally.
I don't like it as much, but it doesn't suffer from the
variable capture problem:
> (mapcar #[x (= x 5)] '(1 3 5 7 9))
(NIL NIL T NIL NIL)
> (mapcar #[x (* x 1.085)] '(12.34 15 10 25.37))
(13.3889 16.275 10.85 27.52645)
> (mapcar #[(x y) (> x y)] '(1 2 3 4 5) '(5 4 3 2 1))
(NIL NIL NIL T T)
> (mapcar #[&rest (list* 'foo rest)] '(1 2 3) '(4 5 6) '(7 8 9))
((FOO 1 4 7) (FOO 2 5 8) (FOO 3 6 9))
>
Definition:
;;; SET-SHARP-BRACKET-READER -- Experimental LAMBDA abbreviation (#2 of 2).
;;; SYNTAX: #[ARGS . BODY]
;;; An abbreviation of (LAMBDA args . body), with two special cases
;;; (feel free to change them, your tastes may differ);
;;; 1. If the ARGS sub-form is the symbol &REST (in any package) then the
;;; form is re-written as (LAMBDA (&rest current-pkg::rest) . body); and
;;; 2. If the ARGS sub-form is any other single symbol then the form is
;;; re-written as (LAMBDA (args) . body).
;;; Otherwise, the form is simply re-written as (LAMBDA args . body).
;;; Examples:
;;; (mapcar #[x (1+ x)] list1)
;;; (mapcar #[(x y) (cons y x)] list1 list2) ; almost a REV-PAIRLIS
;;; (mapcar #[&rest (apply #'some-func fixed-arg1 fixed-arg2 rest)] lists...)
;;;
(defun set-sharp-bracket-reader ()
(macrolet ((ch (x) (char "()[]{}<>" ; idiom for avoiding editor mismatches
(position x '(:lp :rp :lb :rb :lc :rc :la :ra)))))
(flet ((sharp-bracket-reader (s c p)
(declare (ignore c p))
(let* ((args (read s t nil t))
(body (read-delimited-list (ch :rb) s t)))
(etypecase args
(symbol ; special syntax for some common cases
(if (equal (symbol-name '&rest) (symbol-name args))
`(lambda (&rest ,(intern (symbol-name 'rest))) ,@body)
`(lambda (,args) ,@body)))
(list
`(lambda ,args ,@body))))))
(set-dispatch-macro-character #\# (ch :lb) #'sharp-bracket-reader)
(set-macro-character (ch :rb) (get-macro-character (ch :rp) nil)))))
Then there's always this one, which is the same as the previous one
except without the funny reader syntax [and except that it uses a
Scheme-style &REST parameter]:
> (defmacro fn (args &body body)
`(lambda ,(if (listp args) args (list '&rest args)) ,@body))
FN
> (mapcar (fn (x) (= x 5)) '(1 3 5 7 9))
(NIL NIL T NIL NIL)
> (mapcar (fn (x) (* x 1.085)) '(12.34 15 10 25.37))
(13.3889 16.275 10.85 27.52645)
> (mapcar (fn (x y) (> x y)) '(1 2 3 4 5) '(5 4 3 2 1))
(NIL NIL NIL T T)
> (mapcar (fn x (list* 'foo x)) '(1 2 3) '(4 5 6) '(7 8 9))
((FOO 1 4 7) (FOO 2 5 8) (FOO 3 6 9))
>
But typing FN isn't much savings over typing LAMBDA, so I don't
use that one much, either.
My #$ readmacro's main win [and its main technical problem] is its
fixed pre-defined parameter list, with the shell-like $1, $2, etc.
If that's not good enough, I just use LAMBDA.
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607