Hello All,
I'm a bit of a newbie to Lisp and I have been learning how to package
lisp code all nice and neat using asdf. I have a project which
includes a large number of .lisp source files which are named
problem-1.lisp, problem-2.lisp, etc. up to over 100 files and growing.
Some files in the sequence are also not present. So what I would like
to do is load these file programmatically and not have to list every
single file. Check out my code below where I am generating the file
list using a loop macro.
----------- euler.asd ----------------
(require :util)
(defpackage :af.euler-system
(:use :asdf :cl :af.util))
(in-package :afl.euler-system)
(defsystem euler
:name "euler"
:author "Anthony Fairchild <·················@gmail.com>"
:version "1.0"
:maintainer "Anthony Fairchild <·················@gmail.com>"
:licence "BLAH"
:description "Solutions for Project Euler at
http://www.mathschallenge.net"
:long-description ""
:depends-on (:util)
:components (append '((:file "packages") ;; <--- compile error here
(:file "euler" :depends-on '("packages")))
(loop for x from 1 to 300
when (file-exists? (format nil "problem-~d.lisp" x))
collect (list :file (format nil "problem-~d" x) :depends-on
'("packages")))))
;; This is what I had in :components before
#+nil((:FILE "packages")
(:FILE "euler" :DEPENDS-ON ("packages"))
(:FILE "problem-1" :DEPENDS-ON ("packages"))
(:FILE "problem-2" :DEPENDS-ON ("packages"))
(:FILE "problem-4" :DEPENDS-ON ("packages"))
(:FILE "problem-5" :DEPENDS-ON ("packages"))
;;... cut for brevity
(:FILE "problem-112" :DEPENDS-ON ("packages")))
(:FILE "problem-113" :DEPENDS-ON ("packages")))
------------ end of euler.asd ------------
When compiling this I get an error:
The value APPEND is not of type LIST.
[Condition of type TYPE-ERROR]
Restarts:
0: [ABORT] Abort SLIME compilation.
1: [ABORT-REQUEST] Abort handling SLIME request.
2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "worker"
{AF13C99}>)
Backtrace:
0: (ASDF::PARSE-COMPONENT-FORM #<SYSTEM "euler" {AE703E1}> APPEND)
1: (ASDF::PARSE-COMPONENT-FORM NIL (:MODULE "euler" :PATHNAME
#P"/home/anthony/code/Lisp/source/euler/" :NAME "euler" :AUTHOR
"Anthony Fairchild <·················@gmail.com>" :VERSION "1.0" ...))
2: ((SB-C::TOP-LEVEL-FORM (ASDF::PARSE-COMPONENT-FORM NIL (APPLY
#1="#<...>" . #1#))))
3: (SB-FASL::LOAD-FASL-GROUP #<SB-SYS:FD-STREAM for "file
/home/anthony/code/Lisp/source/euler/euler.fasl" {B0F0D19}>)
...
It seems like the (append.... ) code is not getting evaluated before
the (defsystem) is. Does anyone know of a way to fix this? Any help
would be greatly appreciated
Anthony F.
·················@gmail.com wrote:
> (defsystem euler
> :components (append '((:file "packages") ;; <--- compile error here
> (:file "euler" :depends-on '("packages")))
> (loop for x from 1 to 300
> when (file-exists? (format nil "problem-~d.lisp" x))
> collect (list :file (format nil "problem-~d" x) :depends-on
> '("packages")))))
defsystem is a macro, so the "append" is not evaluated. See this for
example:
(defmacro foo (parameter)
(let ((first-list (car parameter)))
(format t "~a" first-list)))
CL-USER > (foo ((bar)))
(BAR)
NIL
CL-USER > (foo (append '((a)) '((b))))
APPEND
NIL
You can use the read-time evaluation macro to execute it at read-time:
CL-USER > (foo #.(append '((a)) '((b))))
(A)
NIL
--
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
·················@gmail.com wrote:
> when (file-exists? (format nil "problem-~d.lisp" x))
BTW: "file-exists?" is not Common Lisp, maybe you mean "probe-file".
--
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
file-exists? is something I wrote using the examples from Practical
Common Lisp. Like I said, I'm a newbie, I appreciate the comment. I
will check out "probe-file".
Thanks,
Anthony F.
·················@gmail.com writes:
> Hello All,
>
> I'm a bit of a newbie to Lisp and I have been learning how to package
> lisp code all nice and neat using asdf. I have a project which
> includes a large number of .lisp source files which are named
> problem-1.lisp, problem-2.lisp, etc. up to over 100 files and growing.
> Some files in the sequence are also not present. So what I would like
> to do is load these file programmatically and not have to list every
> single file. Check out my code below where I am generating the file
> list using a loop macro.
>
> ----------- euler.asd ----------------
> (require :util)
>
> (defpackage :af.euler-system
> (:use :asdf :cl :af.util))
> (in-package :afl.euler-system)
>
> (defsystem euler
> :name "euler"
> :author "Anthony Fairchild <·················@gmail.com>"
> :version "1.0"
> :maintainer "Anthony Fairchild <·················@gmail.com>"
> :licence "BLAH"
> :description "Solutions for Project Euler at
> http://www.mathschallenge.net"
> :long-description ""
> :depends-on (:util)
> :components (append '((:file "packages") ;; <--- compile error here
> (:file "euler" :depends-on '("packages")))
> (loop for x from 1 to 300
> when (file-exists? (format nil "problem-~d.lisp" x))
> collect (list :file (format nil "problem-~d" x) :depends-on
> '("packages")))))
> [...]
> It seems like the (append.... ) code is not getting evaluated before
> the (defsystem) is.
Indeed. DEFSYSTEM is a macro and it determines itself what argument it
wants to evaluate, and what not.
> Does anyone know of a way to fix this? Any help
> would be greatly appreciated
An easy way is to use the reader macro #. :
[24]> '(defsystem euler
:name "euler"
:author "Anthony Fairchild <·················@gmail.com"
:version "1.0"
:maintainer "Anthony Fairchild <·················@gmail.com"
:licence "BLAH"
:description "Solutions for Project Euler at http://www.mathschallenge.net"
:long-description ""
:depends-on (:util)
:components #.(append '((:file "packages") ;; <--- compile error here
(:file "euler" :depends-on '("packages")))
(loop for x from 1 to 300
when (probe-file (format nil "problem-~d.lisp" x))
collect (list :file (format nil "problem-~d" x) :depends-on
'("packages")))))
(DEFSYSTEM EULER :NAME "euler" :AUTHOR "Anthony Fairchild <·················@gmail.com"
:VERSION "1.0" :MAINTAINER "Anthony Fairchild <·················@gmail.com" :LICENCE
"BLAH" :DESCRIPTION
"Solutions for Project Euler at
http://www.mathschallenge.net"
:LONG-DESCRIPTION "" :DEPENDS-ON (:UTIL) :COMPONENTS
((:FILE "packages") (:FILE "euler" :DEPENDS-ON '("packages"))))
Note: the COMPONENTS are computed at READ time!
Another is to write a macro:
(defmacro computed-defsystem (name &rest others &key components &allow-other-keys)
`(defsystem ,name
,@(loop for (k v) on others by (function cddr)
unless (eq k :components) collect k
unless (eq k :components) collect v)
:components ,(eval components)))
[23]> (macroexpand-1 '(computed-defsystem euler
:name "euler"
:author "Anthony Fairchild <·················@gmail.com"
:version "1.0"
:maintainer "Anthony Fairchild <·················@gmail.com"
:licence "BLAH"
:description "Solutions for Project Euler at http://www.mathschallenge.net"
:long-description ""
:depends-on (:util)
:components (append '((:file "packages") ;; <--- compile error here
(:file "euler" :depends-on '("packages")))
(loop for x from 1 to 300
when (probe-file (format nil "problem-~d.lisp" x))
collect (list :file (format nil "problem-~d" x) :depends-on
'("packages"))))))
(DEFSYSTEM EULER :NAME "euler" :AUTHOR "Anthony Fairchild <·················@gmail.com"
:VERSION "1.0" :MAINTAINER "Anthony Fairchild <·················@gmail.com" :LICENCE
"BLAH" :DESCRIPTION
"Solutions for Project Euler at
http://www.mathschallenge.net"
:LONG-DESCRIPTION "" :DEPENDS-ON (:UTIL) :COMPONENTS
((:FILE "packages") (:FILE "euler" :DEPENDS-ON '("packages")))) ;
T
Note: the COMPONENTS are computed at MACRO-EXPANSION time!
One could also have COMPONENTS computed at RUN time:
(eval `(defsystem euler
:name "euler"
:author "Anthony Fairchild <·················@gmail.com"
:version "1.0"
:maintainer "Anthony Fairchild <·················@gmail.com"
:licence "BLAH"
:description "Solutions for Project Euler at http://www.mathschallenge.net"
:long-description ""
:depends-on (:util)
:components ,(append '((:file "packages") ;; <--- compile error here
(:file "euler" :depends-on '("packages")))
(loop for x from 1 to 300
when (probe-file (format nil "problem-~d.lisp" x))
collect (list :file (format nil "problem-~d" x) :depends-on
'("packages"))))))
But with the usual usage of defsystem, all these solutions should be
rather equivalent, since .asd files are not usually compiled for later
execution...
--
__Pascal Bourguignon__ http://www.informatimago.com/
HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.
Thank you for your quick responses. I knew it would be something
simple like that. I'm discovering more and more that I've just
scratched the surface of what lisp is capable of. I'm having a lot of
fun!
Thanks again!
Anthony F.
Ok, I have another hopefully quick question. The reader macro on
(append ...) worked great. The only problem is the current working
directory is my user home directory "/home/anthony" instead of the ASDF
source directory where the files are located. This requires me to use
the fully qualified path which is bad. I did some digging around in
the ASDF documentation and there are ways to get at the files after the
package has been defined using FIND-SYSTEM and FIND-COMPONENT. These
don't work inside the defsystem definition though. Any ideas on how I
can settle these path issues?
Thanks!
AF
Here's my code:
---------------- euler.asd ---------------
(require :util)
(defpackage :af.euler-system
(:use :asdf :cl :af.util))
(in-package :af.euler-system)
(defsystem euler
:name "euler"
:author "Anthony Fairchild <·················@gmail.com>"
:version "1.0"
:maintainer "Anthony Fairchild <·················@gmail.com>"
:licence "BAH!"
:description "Solutions for Project Euler at
http://www.mathschallenge.net"
:long-description ""
:depends-on (:util)
:components #.(append '((:file "packages")
(:file "euler" :depends-on ("packages")))
(loop for x from 1 to 300
when (probe-file (format nil ".clc/source/euler/problem-~d.lisp"
x)) ;;TODO: Hard coded path here. BAD!
collect (list :file (format nil "problem-~d" x) :depends-on
'("packages")))))
·················@gmail.com writes:
> when (probe-file (format nil ".clc/source/euler/problem-~d.lisp"
> x)) ;;TODO: Hard coded path here. BAD!
I haven't followed this thread, but to me it appears that you're
looking for something like:
(probe-file
(make-pathname :directory (append (pathname-directory (user-homedir-pathname)) '(".clc" "source" "euler"))
:name (format nil "problem-~d" x)
:type "lisp"))
Petter
--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?