From: Michael Hudson
Subject: Packages and macros are driving me slowly insane...
Date: 
Message-ID: <m3aenqistg.fsf@atrus.jesus.cam.ac.uk>
Let me explain what I am trying to achieve. It's basically generic
arithmetic. I have a `field' structure that contains functions on how to
add, subtract, etc field elements:

(defstruct (field (:conc-name field))
  (+ #'+ :read-only t)
  (- #'- :read-only t)
  (* #'* :read-only t)
  (/ #'/ :read-only t)
  (-zero 0 :read-only t)
  (-one  1 :read-only t))

(defconstant +default-field+
  (make-field))
As typing

(funcall (field+ field) (field-one field) random-field-element)

would rapidly get tedious, I want to define a macro `with-field-ops'
so that I can write:

(with-field-ops field
  (f+ f1 random-field-element))

I came up with this:

(defmacro with-field-ops (field &body body)
  `(let ((ff+ (field+ ,field))
         (ff- (field- ,field))
         (ff* (field* ,field))
         (ff/ (field/ ,field))
         (f0 (field-zero ,field))
         (f1 (field-one ,field)))
     (declare (ignorable ff+ ff- ff* ff/ f0 f1))
     (macrolet ((f+ (x y) `(funcall ff+ ,x ,y))
                (f- (x y) `(funcall ff- ,x ,y))
                (f* (x y) `(funcall ff* ,x ,y))
                (f/ (x y) `(funcall ff/ ,x ,y)))
       ,@body)))

which is a bit cludgy, but works if I type it at the toplevel. However
if I chuck the above code in a "FIELD" package, this happens:

;; Loading file /home/mwh21/src/c2/16.1/field.lisp ...
;; Loading of file /home/mwh21/src/c2/16.1/field.lisp is finished.
T
CL-USER[9]> (use-package "FIELD")
T
CL-USER[10]> (with-field-ops +default-field+ (f+ f1 f0))
*** - EVAL: the function F+ is undefined

It's obvious why this happens:

CL-USER[13]> (macroexpand '(with-field-ops +default-field+ (f+ f1 f0)))
(LET
  ((FIELD::FF+ (FIELD+ +DEFAULT-FIELD+)) (FIELD::FF- (FIELD- +DEFAULT-FIELD+))
    (FIELD::FF* (FIELD* +DEFAULT-FIELD+)) (FIELD::FF/ (FIELD/ +DEFAULT-FIELD+))
    (FIELD::F0 (FIELD-ZERO +DEFAULT-FIELD+))
    (FIELD::F1 (FIELD-ONE +DEFAULT-FIELD+))
  )
  (DECLARE
    (IGNORABLE FIELD::FF+ FIELD::FF- FIELD::FF* FIELD::FF/ FIELD::F0 FIELD::F1)
  )
  (MACROLET
    ((FIELD::F+ (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF+ ,FIELD::X ,FIELD::Y))
      (FIELD::F- (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF- ,FIELD::X ,FIELD::Y))
      (FIELD::F* (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF* ,FIELD::X ,FIELD::Y))
      (FIELD::F/ (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF/ ,FIELD::X ,FIELD::Y))
    )
    (F+ F1 F0)
) ) ;
T

But it's not obvious (to me) what to do about it... is what I'm doing
bad practice for some reason?

It's a bit like with-slots, I suppose.

TIA,
Michael

From: Joe Marshall
Subject: Re: Packages and macros are driving me slowly insane...
Date: 
Message-ID: <Ldc24.32263$JY6.42649@dfw-read.news.verio.net>
The "FIELD" package should export those symbols that you want to
`capture' in the body of WITH-FIELD-OPS, (namely F+, F-, F*, and F/)


Michael Hudson <·····@cam.ac.uk> wrote in message
···················@atrus.jesus.cam.ac.uk...
> Let me explain what I am trying to achieve. It's basically generic
> arithmetic. I have a `field' structure that contains functions on how to
> add, subtract, etc field elements:
>
> (defstruct (field (:conc-name field))
>   (+ #'+ :read-only t)
>   (- #'- :read-only t)
>   (* #'* :read-only t)
>   (/ #'/ :read-only t)
>   (-zero 0 :read-only t)
>   (-one  1 :read-only t))
>
> (defconstant +default-field+
>   (make-field))
> As typing
>
> (funcall (field+ field) (field-one field) random-field-element)
>
> would rapidly get tedious, I want to define a macro `with-field-ops'
> so that I can write:
>
> (with-field-ops field
>   (f+ f1 random-field-element))
>
> I came up with this:
>
> (defmacro with-field-ops (field &body body)
>   `(let ((ff+ (field+ ,field))
>          (ff- (field- ,field))
>          (ff* (field* ,field))
>          (ff/ (field/ ,field))
>          (f0 (field-zero ,field))
>          (f1 (field-one ,field)))
>      (declare (ignorable ff+ ff- ff* ff/ f0 f1))
>      (macrolet ((f+ (x y) `(funcall ff+ ,x ,y))
>                 (f- (x y) `(funcall ff- ,x ,y))
>                 (f* (x y) `(funcall ff* ,x ,y))
>                 (f/ (x y) `(funcall ff/ ,x ,y)))
>        ,@body)))
>
> which is a bit cludgy, but works if I type it at the toplevel. However
> if I chuck the above code in a "FIELD" package, this happens:
>
> ;; Loading file /home/mwh21/src/c2/16.1/field.lisp ...
> ;; Loading of file /home/mwh21/src/c2/16.1/field.lisp is finished.
> T
> CL-USER[9]> (use-package "FIELD")
> T
> CL-USER[10]> (with-field-ops +default-field+ (f+ f1 f0))
> *** - EVAL: the function F+ is undefined
>
> It's obvious why this happens:
>
> CL-USER[13]> (macroexpand '(with-field-ops +default-field+ (f+ f1 f0)))
> (LET
>   ((FIELD::FF+ (FIELD+ +DEFAULT-FIELD+)) (FIELD::FF- (FIELD-
+DEFAULT-FIELD+))
>     (FIELD::FF* (FIELD* +DEFAULT-FIELD+)) (FIELD::FF/ (FIELD/
+DEFAULT-FIELD+))
>     (FIELD::F0 (FIELD-ZERO +DEFAULT-FIELD+))
>     (FIELD::F1 (FIELD-ONE +DEFAULT-FIELD+))
>   )
>   (DECLARE
>     (IGNORABLE FIELD::FF+ FIELD::FF- FIELD::FF* FIELD::FF/ FIELD::F0
FIELD::F1)
>   )
>   (MACROLET
>     ((FIELD::F+ (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF+ ,FIELD::X
,FIELD::Y))
>       (FIELD::F- (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF- ,FIELD::X
,FIELD::Y))
>       (FIELD::F* (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF* ,FIELD::X
,FIELD::Y))
>       (FIELD::F/ (FIELD::X FIELD::Y) `(FUNCALL FIELD::FF/ ,FIELD::X
,FIELD::Y))
>     )
>     (F+ F1 F0)
> ) ) ;
> T
>
> But it's not obvious (to me) what to do about it... is what I'm doing
> bad practice for some reason?
>
> It's a bit like with-slots, I suppose.
>
> TIA,
> Michael
From: Michael Hudson
Subject: Re: Packages and macros are driving me slowly insane...
Date: 
Message-ID: <m34sdxixml.fsf@atrus.jesus.cam.ac.uk>
"Joe Marshall" <·········@alum.mit.edu> writes:

> The "FIELD" package should export those symbols that you want to
> `capture' in the body of WITH-FIELD-OPS, (namely F+, F-, F*, and F/)

Thanks. Obvious, but I still wouldn;t have thought of it for some
time, methinks.

Cheers,
Michael