Beginner at Common Lisp: Macro Question For Defining Packages on the Fly
-
07-07-2019 - |
Question
Still struggling to understand what best practices are with respect to macros. I'm attempting to write a macro which defines packages on the fly.
(defmacro def-dynamic-package (name)
`(defpackage ,(intern (string-upcase name) "KEYWORD")
(:use :common-lisp)))
This works fine only for expressions such as:
(def-dynamic-package "helloworld")
But fails miserably for something like this:
(defun make-package-from-path (path)
(def-dynamic-package (pathname-name path)))
or
(defun make-package-from-path (path)
(let ((filename (pathname-path)))
(def-dynamic-package filename)))
I understand how most basic macros work but how to implement this one escapes me.
Solution
defpackage is a macro. As such, it's expanded at compile-time, not run-time. What you want is something that is called at run-time in order to make a new package. Therefore, defpackage can't do anything for you.
Fortunately, there's also make-package, which provides defpackage's features as a function. Use it instead of defpackage.
OTHER TIPS
Failure is to be expected here, because a macro is used when its argument should not be evaluated.
In your first make-package-from-path, the def-dynamic-package will receive as argument a list that is EQUAL to the value of the following expression:
(list 'pathname-name 'path)
In your case, you only want a function:
(defun def-dynamic-package (name)
(defpackage (string-upcase name)
(:use :common-lisp)))
BTW, if you check the CLHS, you'll see that the first argument of defpackage needn't be a symbol, but any string designator.