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