Discussion:
help with macro
karol skocik
2011-09-26 07:31:50 UTC
Permalink
Content preview: Hi Lispers, I need a help with a following macro I am trying
to write: When the call site looks like this: (with-typed-arguments (distance)
single-float (+ (distance a b c d) (distance x y z w))) [...]

Content analysis details: (-100.7 points, 5.0 required)

pts rule name description
---- ---------------------- --------------------------------------------------
-0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low
trust
[74.125.82.53 listed in list.dnswl.org]
-100 USER_IN_WHITELIST From: address is in the user's white-list
0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider
(karol.skocik[at]gmail.com)
-0.0 SPF_PASS SPF: sender matches SPF record
0.0 T_DKIM_INVALID DKIM-Signature header exists but is not valid
Archived-At: <http://permalink.gmane.org/gmane.lisp.cl-pro/557>

Hi Lispers,
I need a help with a following macro I am trying to write:

When the call site looks like this:

(with-typed-arguments (distance) single-float
(+ (distance a b c d)
(distance x y z w)))

I want it to expand into something like this:

(+ (DISTANCE (THE SINGLE-FLOAT A) (THE SINGLE-FLOAT B) (THE
SINGLE-FLOAT C) (THE SINGLE-FLOAT D))
(DISTANCE (THE SINGLE-FLOAT X) (THE SINGLE-FLOAT Y) (THE
SINGLE-FLOAT Z) (THE SINGLE-FLOAT W))))

Now, what I have currently is:

(defmacro with-typed-arguments ((&rest functions) argument-type &body body)
(flet ((macrolet-body (fun)
`(,fun (&rest args)
`(funcall #',',fun ,@(iter (for arg :in args)
(collect `(the
,',argument-type ,arg)))))))
`(macrolet (,@(mapcar #'macrolet-body functions))
,@body)))

But it some things I don't understand:

1.) the function called with typed arguments is called using funcall -
not a show stopper, just a style issue. Without funcall the expansion
loops forever since the expansion does not emit the code, but expands
deeper into infinite recursion of macrolets. Can it be fixed somehow?

2.) in the flet macrolet-body, I have a trouble understanding ,',fun
construction next to the funcall - why the "fun" next to funcall can't
be replaced by macrolet-body argument fun with ,,fun ? It is buried in
`` but ,,fun there just got me (for call (macrolet-body +)) -> `(,+
...). Let me show my trouble in the example:

In this definition:
(defmacro with-typed-arguments ((&rest functions) argument-type &body body)
(flet ((macrolet-body (fun)
`(,fun (&rest args)
`(funcall #',,fun ,@(iter (for arg :in args)
(collect `(the
,',argument-type ,arg)))))))
`(macrolet (,@(mapcar #'macrolet-body functions))
,@body)))

this expansion:
(with-typed-arguments (distance) single-float
(+ (distance a b c d)
(distance x y z w)))

results in this:
(MACROLET ((DISTANCE (&REST ARGS)
`(FUNCALL #',DISTANCE
;; <- why is there ,DISTANCE when there is `(... `(... ,,fun
?
,@(ITER
(FOR ARG :IN ARGS)
(COLLECT `(THE SINGLE-FLOAT ,ARG))))))
(+ (DISTANCE A B C D) (DISTANCE X Y Z W)))

3.) package-locks - I want it to work with arithmetic functions
(especially!) defined in CL package. That doesn't work, since I can't
make a macrolet ((+ (&rest args) ...) because of package-locks. I am
happy with SBCL specific fix, using SBCL's
sb-ext:disable-package-locks, or sb-ext:without-package-locks, but I
can't make it work.
Especially, I have a trouble understanding, how do I create a symbol
with package prefix needed in declaration like this:
(declare (sb-ext:disable-package-locks cl::+))

Is there a way to prepend the symbol-package and '::' to the given
symbol? How to construct such fully qualified symbol like cl::+?

Thank you,
Karol
karol skocik
2011-09-26 15:39:54 UTC
Permalink
Content preview: Hi, thanks for help. On Mon, Sep 26, 2011 at 3:02 PM, Scott
McKay wrote: > You're pretty much asking for type inference, but with you
being the one doing the inference. Yes, it's more or less a way to provide
more type hints to SBCL. [...]

Content analysis details: (-100.7 points, 5.0 required)

pts rule name description
---- ---------------------- --------------------------------------------------
-100 USER_IN_WHITELIST From: address is in the user's white-list
0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider
(karol.skocik[at]gmail.com)
-0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low
trust
[74.125.82.53 listed in list.dnswl.org]
-0.0 SPF_PASS SPF: sender matches SPF record
0.0 T_DKIM_INVALID DKIM-Signature header exists but is not valid
Archived-At: <http://permalink.gmane.org/gmane.lisp.cl-pro/558>

Hi,
thanks for help.
You're pretty much asking for type inference, but with you
being the one doing the inference.
Yes, it's more or less a way to provide more type hints to SBCL.

On Mon, Sep 26, 2011 at 4:28 PM, Peter Stirling
First your source code is read by the reader, and symbols are looked up
by their package prefix, or interned in the current package if
unqualified. After this point the raw text that from your lisp file is
thrown away and macro-expansion and compilation is performed using only
the symbols and constants identified/produced by the reader. Since your
macro is trying to shadow symbols rather than generate new ones you only
need to worry about package prefixes at the call site of your macro, and
not in the macro itself
Thanks for explanation. I was confused thinking that reader
subsequently reads more of the form as it is expanded, which is
rubbish.
:use in defpackage will import all external symbols into the defined
package, and since "+" is external in :cl, and it's highly likely that
you are ":use :cl" it wouldn't need a prefix.
(defmacro with-typed-arguments ((name) type &body body)
 (let ((func (gensym)))
   `(let ((,func #',name))
      (declare (sb-ext:disable-package-locks ,name))
      (macrolet ((,name (&rest args)
                        (list* 'funcall ',func
                               (mapcar (lambda (arg)
                                         (list 'the ',type arg))
                                       args))))
        (declare (sb-ext:enable-package-locks ,name))
Should do the expansion you want, but it's not the "right" way in
common-lisp.
Works nicely, thank you! Why do you consider it as not "right"?

Have a nice day.
Karol
Post by karol skocik
Hi Lispers,
(with-typed-arguments (distance) single-float
          (+ (distance a b c d)
             (distance x y z w)))
(+ (DISTANCE (THE SINGLE-FLOAT A) (THE SINGLE-FLOAT B) (THE
SINGLE-FLOAT C) (THE SINGLE-FLOAT D))
    (DISTANCE (THE SINGLE-FLOAT X) (THE SINGLE-FLOAT Y) (THE
SINGLE-FLOAT Z) (THE SINGLE-FLOAT W))))
(defmacro with-typed-arguments ((&rest functions) argument-type &body body)
  (flet ((macrolet-body (fun)
           `(,fun (&rest args)
                                             (collect `(the
,',argument-type ,arg)))))))
1.) the function called with typed arguments is called using funcall -
not a show stopper, just a style issue. Without funcall the expansion
loops forever since the expansion does not emit the code, but expands
deeper into infinite recursion of macrolets. Can it be fixed somehow?
2.) in the flet macrolet-body, I have a trouble understanding ,',fun
construction next to the funcall - why the "fun" next to funcall can't
be replaced by macrolet-body argument fun with ,,fun ? It is buried in
`` but ,,fun there just got me (for call (macrolet-body +)) -> `(,+
(defmacro with-typed-arguments ((&rest functions) argument-type &body body)
  (flet ((macrolet-body (fun)
           `(,fun (&rest args)
                                             (collect `(the
,',argument-type ,arg)))))))
(with-typed-arguments (distance) single-float
          (+ (distance a b c d)
             (distance x y z w)))
(MACROLET ((DISTANCE (&REST ARGS)
             `(FUNCALL #',DISTANCE
          ;; <- why is there ,DISTANCE when there is `(... `(... ,,fun
?
                           (FOR ARG :IN ARGS)
                           (COLLECT `(THE SINGLE-FLOAT ,ARG))))))
  (+ (DISTANCE A B C D) (DISTANCE X Y Z W)))
3.) package-locks - I want it to work with arithmetic functions
(especially!) defined in CL package. That doesn't work, since I can't
make a macrolet ((+ (&rest args) ...) because of package-locks. I am
happy with SBCL specific fix, using SBCL's
sb-ext:disable-package-locks, or sb-ext:without-package-locks, but I
can't make it work.
Especially, I have a trouble understanding, how do I create a symbol
(declare (sb-ext:disable-package-locks cl::+))
Is there a way to prepend the symbol-package and '::' to the given
symbol? How to construct such fully qualified symbol like cl::+?
Thank you,
  Karol
_______________________________________________
pro mailing list
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/pro
Continue reading on narkive:
Loading...