Primarily technical blog on Lisp, .NET, C# development.

Thursday, May 13, 2010

Lisp style

Consider the following snippets of code:


(let ((probed-path)
(not-found t))
(dolist (registry-expression asdf:*central-registry*)
(when not-found
(setf probed-path (eval registry-expression)))
(when (probe-file (merge-pathnames "asd-library.asd" probed-path))
(setf not-found nil)))
probed-path)

(first (remove-if #'null
(mapcar #'(lambda (x)
(when (probe-file
(merge-pathnames "asd-library.asd" (eval x)))
(eval x)))
asdf:*central-registry*)))

Both codes perform the same task. The first one is more like a procedural/imperative code in style than the more functional second one.

By the way, they return the path for a registered library. It is not very useful since ADSF provides the same thing easily with a single function call:

(asdf:system-relative-pathname :asd-library "")

But I like to get back to it as a reference of lisp styles.

Thursday, April 29, 2010

How to make Postmodern ignore incomplete mapped DAO

Yesterday I was working with a database using Postmodern (http://marijn.haverbeke.nl/postmodern/) and I ran into an issue trying to adding a column to one of my databases. 

According to its current implementation, postmodern raises an error if the DAO and the table scheme are not matching. In order words, the DAO class must have all fields from the table it maps to. 

In a real world environment, a web application running live for example, it might not be acceptable to bring the application down just because a new column was added to the table it uses. 

Sometimes, depending on the database design, a table can contain information from several DAO's, specially if they have a parent-child object relationship. 

In order to remove this validation from postmodern allowing you to have DAO's mapping to a subset of the fields of a table all it is needed is a little patch on the postmodern table.lisp file on the function as follows:

(defun dao-row-reader (class)
  "Defines a row-reader for objects of a given class."
  (row-reader (query-fields)
    (let ((column-map (append *custom-column-writers* (dao-column-map class))))
      (loop :while (next-row)
            :collect (let ((instance (allocate-instance class)))
                       (loop :for field :across query-fields
                             :for writer := (cdr (assoc (field-name field) column-map :test #'string=))
                             :do (etypecase writer
                                   (null (next-field field))
                                   (symbol (setf (slot-value instance writer) (next-field field)))
                                   (function (funcall writer instance (next-field field)))))
                       (initialize-instance instance)
                       instance)))))

Compare with the current version code where if the field is not found it raises an error:

(defun dao-row-reader (class)
  "Defines a row-reader for objects of a given class."
  (row-reader (query-fields)
    (let ((column-map (append *custom-column-writers* (dao-column-map class))))
      (loop :while (next-row)
            :collect (let ((instance (allocate-instance class)))
                       (loop :for field :across query-fields
                             :for writer := (cdr (assoc (field-name field) column-map :test #'string=))
                             :do (etypecase writer
                                   (null (error "No slot named ~a in class ~a. DAO out of sync with table, or incorrect query used."
                                                (field-name field) (class-name class)))
                                   (symbol (setf (slot-value instance writer) (next-field field)))
                                   (function (funcall writer instance (next-field field)))))
                       (initialize-instance instance)
                       instance)))))

Friday, April 9, 2010

Save Lisp and Die

If you are running SBCL and are using threads, this is the way I found out that works for me to stop the threads before saving the core.

(dolist (thread (sb-thread:list-all-threads))
    (unless (eq thread sb-thread:*current-thread*)
      (sb-thread:terminate-thread thread)))
 
then you can run...

(sb-ext:save-lisp-and-die "core-file")
 
I am using SBCL 1.0.36 64bit on a Linux Ubuntu 9.10 64bit.

Wednesday, January 20, 2010

Installing SBCL + SLIME on Ubuntu 9.10

Today I tried to upgrade my lisp environment that is using clbuild to keep track of the packages just to be annoyed by its failure. I was just trying to check how hard it would be to do that in my everyday environment. Because of the failure I decided to try other alternatives. This time I tried Lispy which is is defined as (from their website) http://common-lisp.net/project/lispy/:

"Lispy is a library manager for Common Lisp, written in Common Lisp. All of its dependencies except for GPG (with which signed maps and releases are verified) are written in portable Common Lisp. With this approach you should only need a Lisp implementation installed to get started. The Lispy project has two goals:
  1. Implement an easy to use, portable library manager.
  2. Provide a wealth of ready to install libraries."
 Ok. I liked the concept. I followed their guide and was able to have it working on my sbcl 1.0.29 version alrady installed on the machine. I only had one issue because it couldn't find the gpg key. I had to serach for it using a different server:

$ gpg --keyserver subkeys.pgp.net --search-key 0x7CF49723

All was well but I decided to also get the latest from sbcl (1.0.34) and slime as well.

Installing sbcl was very straight forward and I had no issues. Installing slime however was a pain. I got it from the cvs and I set it up just like the getting started page suggested but I could not get to the slime-repl buffer. So after searching the page for known issue I found this:
 
The REPL moved to a contrib. Instead of (slime-setup), place
(slime-setup '(slime-fancy slime-asdf)) into your ~/.emacs.
 
So I ended up with a different .emacs file then before:
 
(add-to-list 'load-path "your-path-to-slime")
(require 'slime)
(add-hook 'lisp-mode-hook (lambda () (slime-mode t)))
(add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode t)))
(setq inferior-lisp-program "sbcl")
(slime-setup '(slime-fancy slime-asdf))
 
Next post I will tell my journey to get a web site running on the good old hunchentoot. 

Wednesday, January 6, 2010

Connecting to a database from Lisp

This is another reminder to myself on how to connect to a database on Lisp using cl-sql through odbcunix.

(use-package :cl-sql)
(connect '("dsn" "user" "password") :database-type :odbc)
(query "select * from table_a")