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