Sunday, May 2, 2010

Learning Lisp

This journal was originally posted to Google Wave on February 7, 2010 and edited incrementally. The resulting discussions are not yet included.

I've heard a lot about Lisp, especially now that I'm in an AI Programming course in college (but it's mainly regarded as a relic in there). I love JavaScript's functional features, but I hadn't managed to dive into their source until now. I'm using Common Lisp for now, with some elisp along the way, although Scheme probably won't be far behind. So this is going to start out as a journal of my experiences.

Background: I know about eight programming languages already, and feel that I can learn any I like. My favorites so far are JavaScript and then Python, precisely because of the Lispy features, so I think I'll love Lisp once I'm fluent in it. On the other hand, I have only programmed as a hobby so far. Keep that in mind if you try Lisp out yourself; your mileage may vary.

I installed clisp+slime using this guide: http://www.osix.net/modules/article/?id=912

I'm using this tutorial: http://www.gigamonkeys.com/book/

2/7/10

I can think of two gotchas I've run into so far: a function body doesn't get wrapped in parentheses, and the first parenthesis goes before the called function's name, not after. Oh, and lists aren't supposed to be comma-delimited.

Naturally, macros are kind of hard to grasp. But I finally decided the most concise description is lazily-evaluated functions, based on the tutorial's explanation.

Right now I'm wondering how to do classes (prototypes?!), although I saw define-class and define-method mentioned in library code. But I'll wait until the tutorial gets to those.

2/8/10


For my inaugural Lisp project I'm implementing the JavaScript object model into Common Lisp. I'm learning a lot about CL's Lisp-2 nature and thinking I'll like Scheme more. But I won't decide that until I've mastered the essential features of CL such as macros and CLOS. (Note to self: Those ugly punctuation doo-hickies are called "read macros.")

But I really need to learn how to debug in emacs+slime+clisp. For that matter I need to learn to use the REPL for programming.

2/11/10

Because Common Lisp is a Lisp-2, that is a Lisp with two namespaces for variables and functions:

  • (fdefinition `foo) is the best place to SETF a global/dynamic function, if the global function FOO is already defined. I hack this up by saying (defun foo () ) before I need to SETF it.

  • If a function is instead assigned as a variable it must be called with (funcall foo arg0 arg1 ...) or (apply foo args).

  • To bind a function in the local/lexical scope and not need to call it with FUNCALL/APPLY you must alias it:
    (let ((foo (lambda ()
    #| ... |#)))
    (flet ((foo (&rest args)
    (apply foo args)))
    ;Now we can call it without FUNCALL:
    (foo)))

  • Note that the above code demonstrates what "Lisp-2" means: The function FOO is in a different namespace than the variable FOO, and their values are not inherently related. The function FOO can be get'ed with #'foo.


Why?

The Common Lisp community explains that the power of CL macros justifies the Lisp-2 nature. I am not yet qualified to give an opinion on the matter.

2/13/10

The LOOP macro had me stuck for a long while (no pun intended) on a syntax error. I finally got that cleared up, but now I have an infinite loop - bah. Anyway, here are the two things I learned, using http://www.ai.sri.com/pkarp/loop.html as my primary reference... (The chapter in Practical Common Lisp helped too, but only by mentioning the word "do" - I got too excited to keep reading.)

  • Sentry variables for a 'while' loop must be assigned outside the loop itself, in a LET for example. ("for x from y" might work too; I didn't check. But "for x = y" makes that assignment every iteration.)

  • The 'do' after the condition-form of your 'while' is there for a reason. This is what kept me stumped for a few days, because the error just said "syntax error" instead of "'do' expected." I decided to put the 'do' on the same line as the 'while' since I don't see any reason they might ever be separated.


2/16/10

In JavaScript, this is a pseudo-variable that changes for each function but cannot be assigned to. I wanted to make my JS functions syntactically similar to native Lisp functions, so I declared the function's lambda list and body as parameters to the function that manufactures JS functions (the Function constructor).

I managed to add this to the list of arguments passed from outside, and declared it in the lambda list. But then I needed to declare a new function using a (list "variable" "like" "this" "one") as the lambda list and the passed-in body. That didn't work; apparently the lazy compiler insists on knowing what each function looks like at compile-time. </self-deprecating-sarcasm>

Alright, enough about JS mechanics; here's the solution I got on a forum:

(defvar *this* "JavaScript details")
(defun makefun (name lambda)
(labels ((havefun (&rest args)
(let ((*this* "more details"))
(apply lambda args))))
#'havefun))
(funcall (makefun "will travel" (lambda ()
(print *this*))))


I didn't compile that, but it should print "more details." What's sad is that I had read about special variables shortly before asking that question (a day at most, I think). I understood them, but for some reason the long way around the tree occurred to me first, as always.

One good thing about this way (other than that it works, isn't a hack, and looks cleaner) is that JavaScript's other variable that mysteriously shows up in every function with a different value - arguments - doesn't require that so many (two) pieces of code be changed in order to accommodate it.

No comments: