vimplugin for eclipse

vimplugin for Eclipse

  • Install it using the Eclipse plugin installer and point it to: http://vimplugin.sf.net/update
  • In Window Preferences, locate the vimplugin settings and set the path to your Vim installation (not gVim). (Note: This might not work immediately—ensure you also configure General > Editor > File Associations for the file types you wish to open with Vim.)
  • Open a file and click to focus on it. (I found this workaround in the known issues.)

Re: VIM Sucks

shortly thereafter, VIM returned carrying a shotgun and wearing steel-toed boots. VIM shot emacs in the chest and then kicked Emacs in the head and in the groin. Emacs never was the same again. To this day, Emacs plays with his toy towers of Hanoi puzzle and always has a psychiatrist around in case he feels scared.

Anonymous


Re: VIM Sucks

Not really.vim is a useful editor when u know how to use it. So is emacs.

Senthil


VIM Sucks

vim sucks, alrite?

why not browse right from inside emacs? u get ALL the functionality of emacs right away and it is extensible like crazy and u can do whatever u want!

Anonymous


Re: VIM Sucks

i once went to a bar. the night was young. the crowd was crazy. the air was electric. and then it happened. emacs kicked vim's ass and threw him on floor. vim 'whim'pered and ran away in shame.

Anonymous

using ptags.py for tag file

  1. Place the ptags.py file in your $PATH.
  2. From the project directory containing your Python project, run the following command:
find . -name "*.py" -print | xargs ptags.py

I was previously using various inefficient methods to achieve this.

Soc application accepted

Wow! My Google Soc application to the Python Software Foundation got accepted. My mentor will be George D. Montana. Thank you, G-SOC and PSF.


Whee! Have fun, mister.

sajith


Awesome!!!

Great news da! All the best.

~Kirubakaran.

Anonymous


oh sure, thanks sajith.

Senthil


Re: Awesome!!!

Thanks kiruba, brother.

Senthil


Wow! Congrats! I was using urllib2 recently and felt it can be made easier. I like Java's Apache HttpClient.

pramodbiligiri


thanks pramod. just got started with. thanks for the pointer, have never used Apache HttpClient, but once familiar with the task, should be a good idea to look into it also.

Senthil

PCL : Syntax and Semantics

Syntax and Semantics

What's with All the Parentheses?

  • Extensive use of parentheses and prefix notation.
  • When John McCarthy first invented Lisp, he intended to implement a more Algol-like syntax, which he called M-expressions.
  • The project of defining M-expressions precisely and compiling them or at least translating them into S-expressions was neither finalized nor explicitly abandoned. It just receded into the indefinite future, and a new generation of programmers appeared who preferred [S-expressions] to any FORTRAN-like or ALGOL-like notation that could be devised.

Breaking Open the Black Box

  • In most programming languages, the language processor--whether an interpreter or a compiler--operates as a black box.
  • Language processor is divided into three subsystems:
  • A lexical analyzer breaks up the stream of characters into tokens.
  • And feeds them to a parser that builds a tree representing the expressions in the program, according to the language's grammar.
  • This tree--called an abstract syntax tree--is then fed to an evaluator that either interprets it directly or compiles it into some other language such as machine code.

  • Common Lisp defines two black boxes, one that translates text into Lisp objects and another that implements the semantics of the language in terms of those objects. The first box is called the reader, and the second is called the evaluator.

  • Each black box defines one level of syntax. The reader defines how strings of characters can be translated into Lisp objects called s-expressions.
  • (foo 1 2) is legal s-expression whereas ("foo" 1 2) is not, because a list starting with string has no meaning.

  • This split of Black Box into two has a couple of consequences:

  • One is that you can use s-expressions, as an externalizable data format (remember the file database example) for data other than source code, using READ to read it and PRINT to print it.
  • The other consequence is that since the semantics of the language are defined in terms of trees of objects rather than strings of characters, it's easier to generate code within the language than it would be if you had to generate code as text.

  • Generating code completely from scratch is only marginally easier--building up lists vs. building up strings is about the same amount of work. The real win, however, is that you can generate code by manipulating existing data. (This is the basis of macros in lisp)

S-expressions

  • Elements of s-expressions are lists and atoms
  • Lists are delimited by parentheses and can contain any number of whitespace-separated elements. (Recursion here)
  • Atoms are everything else.
  • Comments--which aren't, technically speaking, s-expressions--start with a semicolon, extend to the end of a line, and are treated essentially like whitespace.

  • Since lists are syntactically so trivial, the only remaining syntactic rules you need to know are those governing the form of different kinds of atoms (numbers, strings and names)

  • Numbers are fairly straightforward: any sequence of digits--possibly prefaced with a sign (+ or -), containing a decimal point (.) or a solidus (/), or ending with an exponent marker--is read as a number. E.g: 123, 3/7, 1.0, 1.0e0, 1.0d0, 1.0e-4, +42, -42

  • All rationals are internally represented in a simplified form.

  • On the other hand, 1.0, 1.0d0, and 1 can all denote different objects because the different floating-point representations and integers are different types.

  • Strings are enclosed in double quotes. Within a string a backslash (\) escapes the next character, causing it to be included in the string regardless of what it is. The only two characters that must be escaped within a string are double quotes and the backslash itself.

  • Names used in Lisp programs, such as FORMAT and hello-world, and db are represented by objects called symbols.

  • Almost any character can appear in a name. Whitespace characters cannot appear, because the elements of the list are separated by whitespace.

  • No periods only name.
  • Open and close parentheses, double and single quotes, backtick, comma, colon, semicolon, backslash, and vertical bar are for syntactic purposes in lisp. If wish to include them in name, precede with backslash or two vertical bars.

  • While reading names, the reader converts all unescaped characters in a name to their uppercase equivalents. That's why REPL prints the upper case name.

  • Standard style, these days, is to write code in all lowercase and let the reader change names to uppercase.

  • The reader interns symbols--after it has read the name and converted it to all uppercase, the reader looks in a table called a package for an existing symbol with the same name. If can't find one, create a new symbol and add it to the table or return the symbol as already in the table.

  • Hyphenated names is a convention.

  • Global variables are given names that start and end with *
  • Constants are given names, starting and ending with +.
  • Few programmers, define name starting with % and %%.

  • The syntax of list, number, strings and symbols represent a good amount of lisp programs.

x             ; the symbol X
()            ; the empty list
(1 2 3)       ; a list of three numbers
("foo" "bar") ; a list of two strings
(x y z)       ; a list of three symbols
(x 1 "foo")   ; a list of a symbol, a number, and a string
(+ (* 2 3) 4) ; a list of a symbol, a list, and a number.

An only slightly more complex example is the following four-item list that contains two symbols, the empty list, and another list, itself containing two symbols and a string:

(defun hello-world ()
  (format t "hello, world"))

S-expressions as Lisp Forms

  • Common Lisp's evaluation rule defines a second level of syntax that determines which s-expressions can be treated as Lisp forms.
  • Any atom--any nonlist or the empty list--is a legal Lisp form as is any list that has a symbol as its first element.
  • For purposes of discussion, you can think of the evaluator as a function that takes as an argument a syntactically well-formed Lisp form and returns a value, which we can call the value of the form.
  • The simplest Lisp forms, atoms, can be divided into two categories: symbols and everything else.
  • Symbol, evaluated as a form, is considered the name of a variable and evaluates to the current value of the variable.
  • For instance, the symbol PI names a constant variable whose value is the best possible floating-point approximation to the mathematical constant pi.
  • All other atoms--numbers and strings are the kinds you've seen so far--are self-evaluating objects.
  • It's also possible for symbols to be self-evaluating in the sense that the variables they name can be assigned the value of the symbol itself. Two important constants that are defined this way are T and NIL, the canonical true and false values.
  • Another class of self-evaluating symbols are the keyword symbols--symbols whose names start with :.
  • To determine what kind of form a given list is, the evaluator must determine whether the symbol that starts the list is the name of a function, a macro, or a special operator.

Function Calls

  • The evaluation rule for function call forms is simple: evaluate the remaining elements of the list as Lisp forms and pass the resulting values to the named function.
(function-name argument*)
  • Thus, the following expression is evaluated by first evaluating 1, then evaluating 2, and then passing the resulting values to the + function, which returns 3:
(+ 1 2)

Special Operators

  • Because all the arguments to a function are evaluated before the function is called, there's no way to write a function that behaves like the IF operator.
  • To solve this problem, Common Lisp defines a couple dozen so-called special operators, IF being one, that do things that functions can't do. There are 25 in all, but only a small handful are used directly in day-to-day programming.
  • The rule for IF is pretty easy: evaluate the first expression. If it evaluates to non-NIL, then evaluate the next expression and return its value. Otherwise, return the value of evaluating the third expression or NIL if the third expression is omitted.
  • An even simpler special operator is QUOTE, which takes a single expression as its "argument" and simply returns it, unevaluated.
  • QUOTE is used commonly enough that a special syntax for it is built into the reader. Instead of writing the following:
(quote (+ 1 2))

you can write this:

'(+ 1 2)

This syntax is a small extension of the s-expression syntax understood by the reader. From the point of view of the evaluator, both those expressions will look the same: a list whose first element is the symbol QUOTE and whose second element is the list (+ 1 2).15

Macros:

  • While special operators extend the syntax of Common Lisp beyond what can be expressed with just function calls, the set of special operators is fixed by the language standard. Macros, on the other hand, give users of the language a way to extend its syntax.
  • The evaluation of a macro form proceeds in two phases: First, the elements of the macro form are passed, unevaluated, to the macro function. Second, the form returned by the macro function--called its expansion--is evaluated according to the normal evaluation rules.

  • For instance, when you compile a whole file of source code with the function COMPILE-FILE, all the macro forms in the file are recursively expanded until the code consists of nothing but function call forms and special forms. This macroless code is then compiled into a FASL file that the LOAD function knows how to load.

  • Since the evaluator doesn't evaluate the elements of the macro form before passing them to the macro function, they don't need to be well-formed Lisp forms.

  • In other words, each macro defines its own local syntax. For instance, the backwards macro from Chapter 3 defines a syntax in which an expression is a legal backwards form if it's a list that's the reverse of a legal Lisp form.

  • Macros (while syntactically similar to functions) provide an exciting hook into the compiler.

Truth, Falsehood and Equality

  • T for True, NIL for False value and everything else is True.
  • The tricky thing about NIL is that it's the only object that's both an atom and a list: in addition to falsehood, it's also used to represent the empty list.
  • nil, (), 'nil, '() evaluate to NIL.
  • t, 't evaluate to T.
  • Common Lisp provides a number of type-specific equality predicates: = is used to compare numbers, CHAR= to compare characters, and so on.
  • EQ tests for "object identity"--two objects are EQ if they're identical. (Don't use as they are implementation dependent)
  • Thus, Common Lisp defines EQL to behave like EQ except that it also is guaranteed to consider two objects of the same class representing the same numeric or character value to be equivalent.
  • EQUAL loosens the discrimination of EQL to consider lists equivalent if they have the same structure and contents, recursively, according to EQUAL. EQUAL also considers strings equivalent if they contain the same characters.
  • EQUALP is similar to EQUAL except it's even less discriminating. It considers two strings equivalent if they contain the same characters, ignoring differences in case.

Formatting Lisp Code

  • The indentation should reflect the structure of the code.
  • Macro and special forms that implement control constructs are typically indented a little differently: the "body" elements are indented two spaces relative to the opening parenthesis of the form.
(defun print-list (list)
  (dolist (i list)
    (format t "item: ~a~%" i)))
  • Re-indent a whole expression by positioning the cursor on the opening parenthesis and typing C-M-q.
  • Or you can re-indent the whole body of a function from anywhere within it by typing C-c M-q.
  • Finally, comments should be prefaced with one to four semicolons depending on the scope of the comment as follows:
  • ;;;; four colon comments for file header.
  • ;;; three colon for paragraph.
  • ;; for the code following, which is indented along with code.

PCL: A Practical Database

Practical: A Simple Database

  • In this chapter you'll write a simple database for keeping track of CDs.
  • Common Lisp provides three distinct kinds of operators: functions, macros, and special operators.

CDs and Records

  • To keep track of CDs that need to be ripped to MP3s and which CDs should be ripped first, each record in the database will contain the title and artist of the CD, a rating of how much the user likes it, and a flag saying whether it has been ripped.
  • We need a way to represent a single database record.
  • User defined class - CLOS (Common Lisp Object System)
CL-USER> (list 1 2 3)
(1 2 3)
  • A plist is a list where every other element, starting with the first, is a symbol that describes what the next element in the list is. Symbol can be thought of as a name.
  • For the symbols that name the fields in the CD database, you can use a particular kind of symbol, called a keyword symbol.
CL-USER> (list :a 1 :b 2 :c 3)
(:A 1 :B 2 :C 3)
  • Function GETF, which takes a plist and a symbol and returns the value in the plist following the symbol.
CL-USER> (getf (list :a 1 :b 2 :c 3) :c)
3
  • make-cd that will take the four fields as arguments and return a plist representing that CD.
CL-USER> (defun make-cd(title artist rating ripped)
       (list :title title :artist artist :rating rating :ripped ripped))
MAKE-CD
  • DEFUN tells us that this form is defining a new function.
  • When make-cd is called, the arguments passed to the call will be bound to the variables in the parameter list. For instance, to make a record for the CD Roses by Kathy Mattea, you might call make-cd like this:
CL-USER> (make-cd "Roses" "Kathy Mattea" 7 t)
(:TITLE "Roses" :ARTIST "Kathy Mattea" :RATING 7 :RIPPED T)

Filling CDs

  • Larger Constructs to hold records.
  • Also for simplicity you can use a global variable, db, which you can define with the DEFVAR macro. The asterisks (*) in the name are a Lisp naming convention for global variables.
  • You can use the PUSH macro to add items to db. But it's probably a good idea to abstract things a tiny bit, so you should define a function add-record that adds a record to the database.
CL-USER> (defun add-record (cd) (push cd *db*))
ADD-RECORD
  • add-record and make-cd together to add CDs to the database.
CL-USER> (add-record (make-cd "Fly" "Dixie Chicks" 8 t))
((:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
CL-USER> (add-record (make-cd "Roses" "Kathy Mattea" 7 t))
((:TITLE "Roses" :ARTIST "Kathy Mattea" :RATING 7 :RIPPED T)
 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
CL-USER> (add-record (make-cd "Home" "Dixie Chicks" 9 t))
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
 (:TITLE "Roses" :ARTIST "Kathy Mattea" :RATING 7 :RIPPED T)
 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
  • Current value of db by typing db
  • dump-db function that dumps out the database in a more human-readable format.
CL-USER> (defun dump-db()
       (dolist (cd *db*)
         (format t "~{~a:~10t~a~%~}~%" cd)))
DUMP-DB
  • Looping over all the elements of db with the DOLIST macro, binding each element to the variable cd in turn. For each value of cd, you use the FORMAT function to print it.
  • In format, t is shorthand for the stream standard-output.
  • Format directives start with ~ (much the way printf's directives start with %).

One of the coolest FORMAT directives is the ~R directive. Ever want to know how to say a really big number in English words? Lisp knows.

CL-USER> (format nil "~R" 42424242424242424242424242424242424242424242424242)
"forty-two quindecillion, four hundred and twenty-four quattuordecillion, two hundred and forty-two tredecillion, four hundred and twenty-four duodecillion, two hundred and forty-two undecillion, four hundred and twenty-four decillion, two hundred and forty-two nonillion, four hundred and twenty-four octillion, two hundred and forty-two septillion, four hundred and twenty-four sextillion, two hundred and forty-two quintillion, four hundred and twenty-four quadrillion, two hundred and forty-two trillion, four hundred and twenty-four billion, two hundred and forty-two million, four hundred and twenty-four thousand, two hundred and forty-two"

  • ~a directive is the aesthetic directive; it means to consume one argument and output it in a human-readable form. This will render keywords without the leading : and strings without quotation marks.
CL-USER> (format t "~a" "Dixie Chicks")
Dixie Chicks
NIL
CL-USER> (format t "~a" :title)
TITLE
NIL
  • The ~t directive is for tabulating. The ~10t tells FORMAT to emit enough spaces to move to the tenth column before processing the next ~a. A ~t doesn't consume any arguments.
CL-USER> (format t "~a:~10t~a" :artist "Dixie Chicks")
ARTIST:   Dixie Chicks
NIL
  • When FORMAT sees ~{ the next argument to be consumed must be a list. FORMAT loops over that list, processing the directives between the ~{ and ~}.
  • The ~% directive doesn't consume any arguments but tells FORMAT to emit a newline.
  • We could have removed dolist macro call and used the format directive itself:
CL-USER> (defun dump-db()
       (format t "~{~{~a:~10t~a~%~}~%~}" *db*))
DUMP-DB

Improving User Interaction

  • Need some way to prompt the user for a piece of information and read it.
CL-USER> (defun prompt-read(prompt)
       (format *query-io* "~a: " prompt)
       (force-output *query-io*)
       (read-line *query-io*))
PROMPT-READ
  • Format to emit the prompt.
  • FORCE-OUTPUT is necessary in some implementations to ensure that Lisp doesn't wait for a newline.
  • Read a single line of text with the aptly named READ-LINE function.
  • query-io is a global variable, can be recognized by the query-io naming.

Combining make-cd with prompt-read:

CL-USER> (defun prompt-for-cd()
       (make-cd
        (prompt-read "Title")
        (prompt-read "Artist")
        (prompt-read "Rating")
        (prompt-read "Ripped [y/n]")))
PROMPT-FOR-CD
  • prompt-read returns a string, for converting the value to integer, lets use lisp's parse-integer function.
  • parse-integer takes an optional argument :junk-allowed which tells to relax the conversion, if there is any exception.
  • junk-allowed returns nil, if that cannot find the integer, to get over and set it as 0, we use the or macro.
CL-USER> (parse-integer (prompt-read "Rating"))
Rating: 10

10
2
CL-USER> (parse-integer(prompt-read "Rating"):junk-allowed t)
Rating: 10

10
2
CL-USER> (parse-integer(prompt-read "Rating"):junk-allowed t)
Rating: Senthil

NIL
0
CL-USER> (or(parse-integer(prompt-read "Rating"):junk-allowed t)0)
Rating: Senthil

0
  • For y or n prompt, we can use common lisp function Y-OR-N-P, that will reprompt the user till something starting with Y, y, N, n is entered.

So, the final prompt-for-cd will be:

CL-USER> (defun prompt-for-cd ()
       (make-cd
        (prompt-read "Title")
        (prompt-read "Artist")
        (or (parse-integer (prompt-read "Rating"):junk-allowd t)0)
        (y-or-n-p "Ripped [y/n]")))
PROMPT-FOR-CD
  • Let's go for adding a bunch of CDs.
  • You can use the simple form of the LOOP macro, which repeatedly executes a body of expressions until it's exited by a call to RETURN.
CL-USER> (defun add-cds()
       (loop (add-record (prompt-for-cd))
         (if (not (y-or-n-p "Another? [y/n]"))(return))))
ADD-CDS

Saving and Loading the Database

  • save-db function that takes a filename as an argument and saves the current state of the database.
CL-USER> (defun save-db (filename)
       (with-open-file (out filename
                :direction :output
                :if-exists :supersede)
         (with-standard-io-syntax
           (print *db* out))))
SAVE-DB
  • WITH-OPEN-FILE macro opens a file, binds the stream to a variable, executes a set of expressions, and then closes the file. The list following WITH-OPEN-FILE is not function, but list of parameters to WITH-OPEN-FILE, defines the file to open to out stream, direction, output and if the file exists, then supersede.
  • After opening the file, we need to print the content using print command, which is different from format, it prints in lisp recognizable objects which be read back by lisp-reader.
  • WITH-STANDARD-IO-SYNTAX ensures that certain variables that affect the behavior of PRINT are set to their standard values.
CL-USER> (save-db "~/my-cds.db")

If open my-cds.db, we will find the output as in db at CL-USER> prompt.

The function to load the database back is similar.

CL-USER> (defun load-db(filename)
       (with-open-file (in filename)
         (with-standard-io-syntax
           (setf *db* (read in)))))
LOAD-DB
  • The SETF macro is Common Lisp's main assignment operator. It sets its first argument to the result of evaluating its second argument.

Querying the Database

  • Query database.
  • Something LIKE (select :artist "Dixie Chicks")
  • REMOVE-IF-NOT takes a predicate and a list and returns a copy of the list, containing only the elements that satisfy the predicate.
  • The predicate argument can be any function that accepts a single argument and returns a boolean value--NIL for false and anything else for true.
CL-USER> (remove-if-not #'evenp '(1 2 3 4 5 6 7 8 9 10))
(2 4 6 8 10)
  • The funny notation #' is shorthand for "Get me the function with the following name." Without the #', Lisp would treat evenp as the name of a variable and look up the value of the variable, not the function.
  • We can also pass, remove-if-not, an anonymous function.
CL-USER> (remove-if-not #'(lambda (x)(= 0(mod x 2)))' (1 2 3 4 5 6 7 8 9 10))
(2 4 6 8 10)
  • The anonymous function here is (lambda (x) (=0 (mod x 2))) which returns true when x is even, else false.
  • Note that lambda isn't the name of the function--it's the indicator you're defining an anonymous function.
  • To select record using artist, we use the property of plist, getf, and equal to compare and put them all together in a lambda expression.
CL-USER> (remove-if-not
      #'(lambda (cd) (equal (getf cd :artist) "Dixie Chicks")) *db*)
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
  • To wrap the whole expression in a function.
CL-USER> (defun select-by-artist (artist)
       (remove-if-not
        #'(lambda (cd) (equal (getf cd :artist)artist)) *db*))
SELECT-BY-ARTIST
  • Anonymous functions embed the required details like artist.
  • More general select function, with Anonymous function at the next stage.
CL-USER> (defun select (selector-fn)
       (remove-if-not selector-fn *db*))
SELECT
CL-USER> (select #'(lambda (cd) (equal (getf cd :artist) "Dixie Chicks")))
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
  • Anonymous function creation can be wrapped up.
CL-USER> (defun artist-selector (artist)
       #'(lambda (cd) (equal (getf cd :artist) artist)))
ARTIST-SELECTOR
CL-USER> (select (artist-selector "Dixie Chicks"))
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
  • Write a general purpose, selector function generator, a function that, depending upon what arguments is getting passed, will generate a selector function for different fields, or different combination of fields.
  • Keyword parameters
  • Write functions with varying number of parameters, which are bound to the corresponding arguments to the call to the function.
(defun foo (&key a b c) (list a b c))

The only difference is the &key at the beginning of the argument list. However, the calls to this new foo will look quite different. These are all legal calls with the result to the right of the ==>:

(foo :a 1 :b 2 :c 3)  ==> (1 2 3)
(foo :c 3 :b 2 :a 1)  ==> (1 2 3)
(foo :a 1 :c 3)       ==> (1 NIL 3)
(foo)                 ==> (NIL NIL NIL)
  • Need to differentiate between NIL assigned when no value passed vs explicitly assigned NIL.
  • To allow this, when you specify a keyword parameter you can replace the simple name with a list consisting of the name of the parameter, a default value, and another parameter name, called a supplied-p parameter.
  • Supplied-p parameter will set to true or false if an argument was passed to the function call.
(defun foo (&key a (b 20) (c 30 c-p)) (list a b c c-p))

Now the same calls from earlier yield these results:

(foo :a 1 :b 2 :c 3)  ==> (1 2 3 T)
(foo :c 3 :b 2 :a 1)  ==> (1 2 3 T)
(foo :a 1 :c 3)       ==> (1 20 3 T)
(foo)                 ==> (NIL 20 30 NIL)
  • A general selector function, based on the above discussions will be:
(defun where (&key title artist rating (ripped nil ripped-p))
  #'(lambda (cd)
      (and
       (if title    (equal (getf cd :title)  title)  t)
       (if artist   (equal (getf cd :artist) artist) t)
       (if rating   (equal (getf cd :rating) rating) t)
       (if ripped-p (equal (getf cd :ripped) ripped) t))))
  • Updating Existing Records--Another Use for WHERE
(defun update (selector-fn &key title artist rating (ripped nil ripped-p))
  (setf *db*
        (mapcar
         #'(lambda (row)
             (when (funcall selector-fn row)
               (if title    (setf (getf row :title) title))
               (if artist   (setf (getf row :artist) artist))
               (if rating   (setf (getf row :rating) rating))
               (if ripped-p (setf (getf row :ripped) ripped)))
             row) *db*)))
CL-USER> (update (where :artist "Dixie Chicks") :rating 11)
NIL
  • Function to delete rows.
(defun delete-rows (selector-fn)
  (setf *db* (remove-if selector-fn *db*)))
  • Remove Duplication and winning Big
  • When a Lisp expression contains a call to a macro, instead of evaluating the arguments and passing them to the function, the Lisp compiler passes the arguments, unevaluated, to the macro code, which returns a new Lisp expression that is then evaluated in place of the original macro call.
  • The main syntactic difference between a function and a macro is that you define a macro with DEFMACRO instead of DEFUN.
CL-USER>(defmacro backwards (expr) (reverse expr))
CL-USER> (backwards ("hello, world" t format))
hello, world
NIL

When the REPL started to evaluate the backwards expression, it recognized that backwards is the name of a macro. So it left the expression ("hello, world" t format) unevaluated, which is good because it isn't a legal Lisp form. It then passed that list to the backwards code. The code in backwards passed the list to REVERSE, which returned the list (format t "hello, world").

ngwallpaper

I started using Google Code project hosting for the ngwallpaper project. This Python script fetches the wallpaper of the day from the National Geographic website and sets it as your desktop wallpaper.

It currently works on Windows by leveraging Python Windows Extensions (using the SETDESKTOPWALLPAPER attribute from a Windows API call).

Future improvements include: 1. Making it platform-agnostic (support for Windows, Linux, and Mac). 2. Refactoring the code for better structure. 3. Implementing the program as a service or scheduled task. 4. Fixing the issue where the wallpaper resets after a few hours on Windows.