From: Rolf Wester
Subject: Macro question
Date: 
Message-ID: <3C186B17.3641BF44@ilt.fhg.de>
Hi,

I want to write a little language for optical ABCD matrix computation.
At present this is just
for learning Lisp and macros especially.
I define a class abcd:

(defclass abcd   () ((a  :initform 1.0 :initarg :a :accessor a) (b
:initform 0.0 :initarg :b :accessor b)
                     (c  :initform 0.0 :initarg :c :accessor c) (d
:initform 1.0 :initarg :d :accessor d))
              (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))

Then I define a macro that I would like to make the job of defining
optical elements like
lenses, mirrors and so on:

(defmacro def-oe (oe-type y)
  `(progn
     (defclass ,oe-type   (abcd) ((,y  :initform 1.0 :initarg :f
:accessor ,y)))
     (defmethod initialize-instance :after ((,oe ,oe-type) &rest
initargs)
        (setf (c ,oe) (/ -1.0 (,y ,oe)))) ;in the final version this
should also be given as a macro parameter
     (defmacro ,oe-type (name &key ,y)
        `(setf ,name (make-instance ',,oe-type :f ,y)))))

I faced two problems:
1. I could not figure out how to make the macro expand initarg :f  into
something like :,y.
    The same for :f ,y in  `(setf ,name ..)
2. When I type
        (def-oe lens f)
        (lens l1 :f 100.0)
    I get the error message:
    *** - EVAL: variable LENS has no value

I'm running CLISP under WinNT.

Thanks in anticipation.

Rolf Wester

From: Kent M Pitman
Subject: Re: Macro question
Date: 
Message-ID: <sfw667biirg.fsf@shell01.TheWorld.com>
Rolf Wester <······@ilt.fhg.de> writes:

> (defclass abcd ()
>   ((a  :initform 1.0 :initarg :a :accessor a)
>    (b  :initform 0.0 :initarg :b :accessor b)
>    (c  :initform 0.0 :initarg :c :accessor c)
>    (d  :initform 1.0 :initarg :d :accessor d))
>   (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))
> 
> Then I define a macro that I would like to make the job of defining
> optical elements like lenses, mirrors and so on:
> 
> (defmacro def-oe (oe-type y)
>   `(progn
>      (defclass ,oe-type (abcd) 
>        ((,y  :initform 1.0 :initarg :f :accessor ,y)))
>      (defmethod initialize-instance :after
>                 ((,oe ,oe-type) &rest initargs)
>         ;; in the final version this should also be given 
>         ;; as a macro parameter
>         (setf (c ,oe) (/ -1.0 (,y ,oe)))) 
>      (defmacro ,oe-type (name &key ,y)
>         `(setf ,name (make-instance ',,oe-type :f ,y)))))

It's unlikely that ,y is going to work here.  I didn't try your code, but
you plainly mean the "y" from two backquotes out, so that'd be ,',y
probably.

> I faced two problems:
> 1. I could not figure out how to make the macro expand initarg :f  into
>    something like :,y. The same for :f ,y in  `(setf ,name ..)

: is not a readmacro.  It is a primitive piece of token syntax.
:FOO denotes the symbol named "FOO" in the package "KEYWORD".
If you have instead the symbol FOO, you must take its name with
SYMBOL-NAME, as in (SYMBOL-NAME 'FOO) => "FOO", then you must 
intern it anew in the keyword package, as in (INTERN "FOO" "KEYWORD").

But I don't recommend that.  I recommend that the macro call be given the
keyword symbol in the first place OR that you use a non-keyword as an 
init arg.  e.g., arrange to do (def-oe lens f :f) or else arrange to use
f rather than :f as an initarg.  Nothing is wrong with a slotspec like

     (foo :initform 1 :initarg foo :accessor foo)

You just have to do (make-instance .... 'foo 2) 
rather than (make-instance .... :foo 2).
As such, you could just use
 ((,y :initform 1.0 :initarg ,y :accessor ,y))
and
 `(setf ,name (make-instance ',,oe-type ',',y ,',y)))))

> 2. When I type
>         (def-oe lens f)
>         (lens l1 :f 100.0)
>     I get the error message:
>     *** - EVAL: variable LENS has no value

I'm guessing this might be because of your use of ',,oe-type which says
to evaluate oe-type's result once before not doing so.  That is, you put
in LENS, then at one backquote level you evaluate LENS and at the other
backquote level you don't evaluate it.  I think you want to evaluate it
at neither level, so you want ',',oe-type instead.  I'm just guessing though.
It's late and I'm sleepy and too lazy to type this in and try it.

> I'm running CLISP under WinNT.
> 
> Thanks in anticipation.
> 
> Rolf Wester
From: Kenny Tilton
Subject: Re: Macro question
Date: 
Message-ID: <3C1882BE.ABE301FB@nyc.rr.com>
(defclass abcd ()
  ((a :initform 1.0 :initarg :a :accessor a)
   (b :initform 0.0 :initarg :b :accessor b)
   (c :initform 0.0 :initarg :c :accessor c)
   (d :initform 1.0 :initarg :d :accessor d))
  (:default-initargs
      :a 1.0
    :b 0.0
    :c 0.0
    :d 1.0))

(defmacro def-oe (oe-type oe-slot oeBindVar)
  (let ((oe-slot-initarg (intern oe-slot :keyword)))
  `(progn
     (defclass ,oe-type (abcd)
       ((,oe-slot  :initform 1.0 :initarg ,oe-slot-initarg :accessor
,oe-slot)))
     (defmethod initialize-instance :after ((,oeBindVar ,oe-type) &rest
                                                           initargs)
       (setf (c ,oeBindVar) (/ -1.0 (,oe-slot ,oeBindVar)))) ;in the
final version this should be a macro parameter
     (defmacro ,oe-type (name &key ,oe-slot)
       `(setf ,name (make-instance ',',oe-type ,,oe-slot-initarg
,,oe-slot))))))

#+test
(def-oe mirror mirror-slot oe)

#+test
(mirror *mirror-01* :mirror-slot 3)

(defmacro def-oe-final (oe-type oe-slot oeBindVar c-init-form)
  (let ((oe-slot-initarg (intern oe-slot :keyword)))
  `(progn
     (defclass ,oe-type (abcd)
       ((,oe-slot  :initform 1.0 :initarg ,oe-slot-initarg :accessor
,oe-slot)))
     (defmethod initialize-instance :after ((,oeBindVar ,oe-type) &rest
                                                           initargs)
       (setf (c ,oeBindVar) ,c-init-form)) ; this is a macro parameter
     (defmacro ,oe-type (name &key ,oe-slot)
       `(setf ,name (make-instance ',',oe-type ,,oe-slot-initarg
,,oe-slot))))))

#+test
(def-oe-final mirror mirror-slot oe
  (/ -1.0 (mirror-slot oe)))

(defvar *mirror-01*)

#+test
(mirror *mirror-01* :mirror-slot 3)

Rolf Wester wrote:
> 
> Hi,
> 
> I want to write a little language for optical ABCD matrix computation.
> At present this is just
> for learning Lisp and macros especially.
> I define a class abcd:
> 
> (defclass abcd   () ((a  :initform 1.0 :initarg :a :accessor a) (b
> :initform 0.0 :initarg :b :accessor b)
>                      (c  :initform 0.0 :initarg :c :accessor c) (d
> :initform 1.0 :initarg :d :accessor d))
>               (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))
> 
> Then I define a macro that I would like to make the job of defining
> optical elements like
> lenses, mirrors and so on:
> 
> (defmacro def-oe (oe-type y)
>   `(progn
>      (defclass ,oe-type   (abcd) ((,y  :initform 1.0 :initarg :f
> :accessor ,y)))
>      (defmethod initialize-instance :after ((,oe ,oe-type) &rest
> initargs)
>         (setf (c ,oe) (/ -1.0 (,y ,oe)))) ;in the final version this
> should also be given as a macro parameter
>      (defmacro ,oe-type (name &key ,y)
>         `(setf ,name (make-instance ',,oe-type :f ,y)))))
> 
> I faced two problems:
> 1. I could not figure out how to make the macro expand initarg :f  into
> something like :,y.
>     The same for :f ,y in  `(setf ,name ..)
> 2. When I type
>         (def-oe lens f)
>         (lens l1 :f 100.0)
>     I get the error message:
>     *** - EVAL: variable LENS has no value
> 
> I'm running CLISP under WinNT.
> 
> Thanks in anticipation.
> 
> Rolf Wester
From: Rolf Wester
Subject: Re: Macro question
Date: 
Message-ID: <3C1B27B2.9C51AD08@t-online.de>
Hi,

thanks a lot to Kent and Kenny for your comprehensive replies. Below I
attach
the versions I tried along the suggestions given by you. Maybe there are
more
Lisp (Lips macro) beginners who are interested in it.

Lisp macros are really a fascinating kind of higher order programming.

Rolf Wester

----------------------------------------------------------------------------------

(defclass abcd   () ((a  :initform 1.0 :initarg :a :accessor a)
                     (b  :initform 0.0 :initarg :b :accessor b)
                     (c  :initform 0.0 :initarg :c :accessor c)
                     (d  :initform 1.0 :initarg :d :accessor d))
                    (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))

;;;;;;; Verison 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro def-oe1 (oe-type y)
  `(progn
     (defclass ,oe-type   (abcd) ((,y  :initform 1.0 :initarg ,y :accessor
,y)))
     (defmethod initialize-instance :after ((oe ,oe-type) &rest initargs)
        (setf (c oe) (/ -1.0 (,y oe))))
     (defmacro ,oe-type (name v)
        `(setf ,name (make-instance ',',oe-type ',',y ,v)))))

(macroexpand-1 '(def-oe1 linse1 f))
(def-oe1 linse1 f)
(linse1 l1 10.0)
(c l1)
(macroexpand-1 '(linse1 l1 100.0))

;;;;;;; Verison 2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro def-oe2 (oe-type y)
  `(progn
     (defclass ,oe-type   (abcd) ((,y  :initform 1.0 :initarg ,y :accessor
,y)))
     (defmethod initialize-instance :after ((oe ,oe-type) &rest initargs)
        (setf (c oe) (/ -1.0 (,y oe))))
     (defmacro ,oe-type (name f v)
        `(setf ,name (make-instance ',',oe-type ,f ,v)))))

(macroexpand-1 '(def-oe2 linse2 f))
(def-oe2 linse2 f)
(linse2 l2 'f 10.0)
(c l1)
(macroexpand-1 '(linse2 l2 'f 100.0))

;;;;;;; Verison 3 Kenny Tilton
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro def-oe3 (oe-type oe-slot oeBindVar)
  (let ((oe-slot-initarg (intern (symbol-name oe-slot) :keyword)))
  `(progn
     (defclass ,oe-type (abcd)
       ((,oe-slot  :initform 1.0 :initarg ,oe-slot-initarg :accessor
,oe-slot)))
     (defmethod initialize-instance :after ((,oeBindVar ,oe-type) &rest
initargs)
       (setf (c ,oeBindVar) (/ -1.0 (,oe-slot ,oeBindVar))))
     (defmacro ,oe-type (name &key ,oe-slot)
       `(setf ,name (make-instance ',',oe-type ,,oe-slot-initarg
,,oe-slot))))))

(macroexpand-1 '(def-oe3 linse3 f oe))
(def-oe3 linse3 f oe)
(linse3 l3 :f 3)
(c l3)
(macroexpand-1 '(linse3 l3 :f 100.0))

;;;;;;; Verison 4 Kenny Tilton
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro def-oe4 (oe-type oe-slot oeBindVar c-init-form)
  (let ((oe-slot-initarg (intern (symbol-name oe-slot) :keyword)))
  `(progn
     (defclass ,oe-type (abcd)
       ((,oe-slot  :initform 1.0 :initarg ,oe-slot-initarg :accessor
,oe-slot)))
     (defmethod initialize-instance :after ((,oeBindVar ,oe-type) &rest
initargs)
        ,c-init-form) ; this is a macro parameter
;       (setf (c ,oeBindVar) ,c-init-form)) ; this is a macro parameter
     (defmacro ,oe-type (name &key ,oe-slot)
       `(setf ,name (make-instance ',',oe-type ,,oe-slot-initarg
,,oe-slot))))))

(macroexpand-1 '(def-oe4 linse4 f oe
                  (progn (setf (a oe) 1.0)
                         (setf (c oe) (/ -1.0 (f oe))))))
(def-oe4 linse4 f oe
  (progn (setf (a oe) 2.0)
         (setf (c oe) (/ -1.0 (f oe)))))
(linse4 l4 :f 3)
(a l4)
(c l4)
From: Marco Antoniotti
Subject: Re: Macro question
Date: 
Message-ID: <y6cr8pvj8sz.fsf@octagon.mrl.nyu.edu>
Rolf Wester <···········@t-online.de> writes:

> Hi,
> 
> thanks a lot to Kent and Kenny for your comprehensive replies. Below I
> attach
> the versions I tried along the suggestions given by you. Maybe there are
> more
> Lisp (Lips macro) beginners who are interested in it.
> 
> Lisp macros are really a fascinating kind of higher order programming.
> 
> Rolf Wester
> 
> ----------------------------------------------------------------------------------
> 
> (defclass abcd   () ((a  :initform 1.0 :initarg :a :accessor a)
>                      (b  :initform 0.0 :initarg :b :accessor b)
>                      (c  :initform 0.0 :initarg :c :accessor c)
>                      (d  :initform 1.0 :initarg :d :accessor d))
>                     (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))

If you are using both :initarg's and :initform's with the same
constant values, maybe you can do away with the second ones.

(defclass abcd ()
  ((a :initarg :a :accessor a)
   (b :initarg :b :accessor b)
   (c :initarg :c :accessor c)
   (d :initarg :d :accessor d))
  (:default-initargs :a 1.0 :b 0.0 :c 0.0 :d 1.0))


Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.