You can now read my lisp related ramblings at http://cyrusharmon.org/cl/blog/
Cyrus has developed a number of lisp packages, which can be found on his website.
A long time ago, when I didn't understand lisp very well, I had a bunch of questions. For posterity's sake, I leave them below:
1. Why are there so many but so few good open source lisp implementations? It seems there's at least one lisp implementation, emacs lisp, on basically every platfrom anyone cares about. Yet most sane persons would not consider writing applications in emacs lisp. Why can't we unify emacs lisp and common lisp? I'm sure this has been asked countless times and answered even more.
Ok, this question isn't necessarily valid anymore. There are at least 6 good open source common-lisp implementations that I am aware of, and probably more. They can be found elsewhere on cliki, no doubt, but, at a minimum, SBCL, CMUCL, OpenMCL, clisp, ecl, and abcl are all interesting open-source lisps with at least one virtue or another.
As for the emacs/common-lisp unification, this is probably also addressed elsewhere on cliki, but there are two approaches here. One is to rewrite an emacs-like editor with nice lisp integration, syntax-aware editing, etc... and this has been done at least twice with hemlock and, more recently, climacs. climacs seems to have an enthusiastic and active developer community and is progressing nicely. It requires CLIM which, if climacs were ever to approach anything like emacs' ubiquity, still requires substantial work, primarily in making it work well on multiple platforms, at least as I see it. The second approach would be to put a common-lisp engine underneath emacs directly, upgrading the emacs APIs to be common-lisp instead of emacs lisp and then forward-porting gnus, vm, mule, etc... I know folks have thought about doing this before, but I don't know if anyone is actively doing this. ECL seems like it would make an interesting candidate for this.
2. Why is calling foreign functions such a black art? I know people do it, but it looks pretty hairy. Why doesn't swig support various flavors of lisp? Swig supports two schemes and OCAML ferchrisakes, why can't it play nice with, say, openmcl?
Black art? What is black art about this:
CL-USER(8): (define-alien-routine getenv c-string (name c-string)) GETENV CL-USER(9): (define-alien-routine setenv int (name c-string) (value c-string) (replace int)) SETENV CL-USER(10): (getenv "FOO") NIL CL-USER(11): (setenv "FOO" "BAR" 1) 0 CL-USER(12): (getenv "FOO") "BAR"
Of course, fully automagical header file parsing would be even neater, but other than that, what more can you ask? No extra step whatsoever -- calling C is often easier from CL then from C. ;-) --Nikodemus Siivola
Ah, but which version of lisp does this work in? The black art comes from knowing that define-alien-routine is an SBCL thing. What is the corresponding OpenMCL equivalent? CLISP etc... Sure, there are things like UFFI which attempt to unify this, but I would argue that it is knowing all of these little details that turn it into a "black art". Also, I see fully automagical header file parsing as a requirement for really calling C in a nice way. Or at least semi-automagic, as you get with SWIG. SWIG apparently supports sexpr's and there's some code to tweak this into right FFI declarations, but getting this all (unsupported stuff) to work is what makes it, IMHO, a black art.
Have you ever tried to feed non-trivial C-code to SWIG? I have, and concluded that it was less work to code the whole thing anew in CL than annotate the headers for Ruby.
Most CLs provide quite sane FFI's -- and if you need to be portable you can go the UFFI route. How many implementations do you use? It's important to realize that if you keep your core portable (which is easy) you can safely worry about portability when it matters. You wrote for SBCL FFI, and need an OpenMCL port? No problemo -- unless your work is extemely FFI centric the porting is *not going to be a sticking problem, really.
Ok, having played around with OpenMCL's FFI stuff a bit more, I'm willing to admit that:
(defun TIFFOpen (file mode) (with-cstrs ((c-file file) (c-mode mode)) (ccl::external-call "_TIFFOpen" :address c-file :address c-mode :address)))may not exactly qualify as being in the "black art" category. But the points remain that 1) this is a (very) simple example, 2) it's specific to OpenMCL, 3) it's specific to Darwin (although I imagine the _EntryPoint convention is basically the same under most Unixes) and 4) the documentation for more complex examples (pointers to arrays, etc...) is fairly minimal and it's not obvious at first glance how to go about hooking this stuff up properly. However, having done a little bit of it, it is pretty cool. You can even attach gdb to a running openmcl process and debug your C code that's being called from lisp. I suppose this is expected and maybe even obvious, but I found it to be pretty neat and handy.
I'm planning on packaging up this TIFF stuff and posting as an example of how to do FFI with openmcl. This stuff may be obvious to most, but it wasn't to me, so hopefully this will help others avoid banging their heads the same places I banged mine.
3. Following question 1, so everyone (mostly) has (at least) one flavor of lisp on their machine in emacs-lisp. It's free, it runs on most platforms and seems pretty ubiquitous. Yet earlier I complained about the lack of a good free lisp implementation. What's up with emacs-lisp? Why is it unsatisfactory as a general purpose lisp? Why doesn't emacs use a decent version of common-lisp as its language?
Ok, emacs-lisp blows for lots of reasons. Primarily because it predates common-lisp and doesn't do all the things we know and love and expect our lisp implementation to do. -- Cyrus Harmon
4. So how the heck do you get asdf to, when defining a system, load another system? I want to be able to say that module foo requires module bar. But when I do it seems I have to explicitly say which :components in bar I need. I don't want to have to do that and want to be able to just depend on the whole system.
You can add a ":depends-on" argument to the system, such as:
(defsystem :foobar :name "A sample" :depends-on (aserve))
Cool! That coupled with:
(setf asdf:*central-registry* '(*default-pathname-defaults* #p"matrix/" #p"tiff/") )
is exactly what I needed!