Rutils ?

I was excited to try this out when I came across it … but it looks like (today!) the github repo is not in a compilable state, at least on Allegro CL.

CL-USER(44): (ql:quickload 'rutils)
To load "rutils":
  Load 1 ASDF system:
    rutils
; Loading "rutils"
[package editor-hints.named-readtables]...........
[package rutils.readtable]........................
[package rutils.core].............................
[package rutils.misc].............................
[package rutils.anaphora].........................
[package rutils.list].............................
[package rutils.string]...........................
[package rutils.hash-table].......................
[package rutils.sequence].........................
[package rutils.pair].............................
[package rutils.tree].............................
[package rutils.array]............................
[package rutils.abbr].............................
[package rutils]..................................
[package rutil].; While EVALUATING an unknown function in
                #P"/usr/local/google/home/agam/quicklisp/dists/quicklisp/software/rutils-20140425-git/core/readtable.lisp":
Error: There is no readtable named :RUTILS.READTABLE.RUTILS-READTABLE.
  [condition type: SIMPLE-ERROR]

Update:

It works fine on SBCL(!)

I think this is because Allegro CL (which, in its defense, is trying to be clever) supports a named readtable feature that is getting triggered by the text at the top of this file. Oh well, I guess I’ll have to stick with SBCL.

Anyway, coming back to rutils: read the announcement. I for one totally agree with this goal of collecting and consolidating utility code, and as a newbie, will do my best to learn as much as I can from it!

BotWorld -> BotVerse

I came across this paper (actually a literate haskell document, pretty cool!) from MIRI. (What’s MIRI ? I suppose someone finally convinced the “Singularity Institute” they had a terrible name) So I’ve come up with a worthy side project for a while: coming up with an interactive counterpart of the same written in Common Lisp. It won’t be easy, since (1) I’m sort of a noob right now, and (2) this was created by a couple of people working full-time for a month, but it should be fun and rewarding. Since they call it BotWorld, I can call my version BotVerse 🙂

Update: I tried this, but translating haskell to lisp is no fun … also, I don’t like some parts of how this is implemented, and I’ll ping back here when I have something to show!

Defstruct and Defclass as macros

The SBCL version

(macroexpand-1 '(defstruct spoint (x y)))

(PROGN
 (SB-KERNEL:WITH-SINGLE-PACKAGE-LOCKED-ERROR (:SYMBOL 'SPOINT
                                              "defining ~A as a structure"))
 (SB-KERNEL::%DEFSTRUCT '#
                        '#(#
                           #)
                        (SB-C:SOURCE-LOCATION))
 (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
   (SB-KERNEL::%COMPILER-DEFSTRUCT '#
                                   '#(#
                                      #)))
 (DECLAIM (FTYPE (SB-INT:SFUNCTION (&KEY (:X T)) SPOINT) MAKE-SPOINT))
 (DEFUN MAKE-SPOINT (&KEY ((:X #:DUM947) Y))
   (SB-KERNEL::%MAKE-STRUCTURE-INSTANCE-MACRO
    # '((:SLOT T . 1)) #:DUM947))
 (LOCALLY
  (DECLARE (NOTINLINE SB-KERNEL:FIND-CLASSOID))
  (SETF (SB-KERNEL::STRUCTURE-CLASSOID-CONSTRUCTOR
         (SB-KERNEL:FIND-CLASSOID 'SPOINT))
          #'MAKE-SPOINT))
 'SPOINT)

(macroexpand-1 '(defclass point () (x y)))

(PROGN
 (EVAL-WHEN (:COMPILE-TOPLEVEL)
   (SB-PCL::%COMPILER-DEFCLASS 'POINT 'NIL 'NIL '(Y X)))
 (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE)
   (LET ()
     (SB-PCL::LOAD-DEFCLASS 'POINT 'STANDARD-CLASS 'NIL
                            (LIST
                             (LIST* :NAME 'X :READERS 'NIL :WRITERS 'NIL
                                    :INITARGS 'NIL 'NIL)
                             (LIST* :NAME 'Y :READERS 'NIL :WRITERS 'NIL
                                    :INITARGS 'NIL 'NIL))
                            (LIST :DIRECT-DEFAULT-INITARGS NIL) 'NIL 'NIL
                            '(Y X) (SB-C:SOURCE-LOCATION) 'NIL))))

The Allegro CL version

(macroexpand-1 '(defstruct spoint (x y)))

(PROGN (PROGN (EVAL-WHEN (COMPILE)
                (EXCL::CHECK-LOCK-DEFINITIONS-COMPILE-TIME 'SPOINT :TYPE 'DEFSTRUCT (SYSTEM:CE-GET 'SPOINT 'EXCL::%STRUCTURE-DEFINITION)))
              (EVAL-WHEN (LOAD EVAL) (EXCL::CHECK-LOCK-DEF-DEFSTRUCT 'SPOINT)) (RECORD-SOURCE-FILE 'SPOINT :TYPE :TYPE))
       (PROGN (EVAL-WHEN (COMPILE) (PUSH 'SPOINT-X EXCL::.FUNCTIONS-DEFINED.)) (RECORD-SOURCE-FILE 'SPOINT-X)
              (SETF (SYMBOL-FUNCTION 'SPOINT-X) (EXCL::GET-BUILT-IN-ACCESSOR 1)))
       (DEFSETF SPOINT-X EXCL::DEFSTRUCT-SLOT-DEFSETF-HANDLER 1) (DEFUN MAKE-SPOINT (&KEY (#:X Y)) (SYSTEM::NEW-STRUCT 'SPOINT #:X))
       (DEFINE-COMPILER-MACRO MAKE-SPOINT (&WHOLE EXCL::WHOLE &REST REST)
         (LET ((EXCL::INITS #)) (IF EXCL::INITS (EXCL::BQ-LIST `LET* EXCL::INITS #) EXCL::WHOLE)))
       (EXCL::DEFINEF COPY-SPOINT (SYMBOL-FUNCTION 'COPY-STRUCTURE)) (EXCL::DEFINEF SPOINT-P (EXCL::GET-DD-PREDICATE-CLOSURE 'SPOINT))
       (EVAL-WHEN (LOAD EVAL)
         (LET ((EXCL::NEW #))
           (EXCL::COMPUTE-STRUCT-CPL EXCL::NEW)
           (EXCL::NOTIFY-CLOS-OF-NEW-STRUCTURE 'SPOINT EXCL::NEW)
           (EVAL-WHEN (LOAD EVAL) (SETF # EXCL::NEW))))
       (EVAL-WHEN (COMPILE)
         (LET ((EXCL::OLD #) (EXCL::NEW #))
           (SETF (EXCL::DD-INCLUDED-BY EXCL::NEW) (IF EXCL::OLD #))
           (EXCL::COMPUTE-STRUCT-CPL EXCL::NEW)
           (EXCL::NOTIFY-CLOS-OF-NEW-STRUCTURE 'SPOINT EXCL::NEW SYSTEM:*COMPILATION-UNIT-ENVIRONMENT*)
           (SYSTEM:CE-PUTPROP 'SPOINT EXCL::NEW 'EXCL::%STRUCTURE-DEFINITION)))
       ...)

(macroexpand-1 '(defclass point () (x y)))

(PROGN NIL (EVAL-WHEN (COMPILE) (EXCL::CHECK-LOCK-DEFINITIONS-COMPILE-TIME 'POINT :TYPE 'DEFCLASS (FIND-CLASS 'POINT NIL)))
       (RECORD-SOURCE-FILE 'POINT :TYPE :TYPE)
       (EXCL::ENSURE-CLASS-1 'POINT :DIRECT-SUPERCLASSES 'NIL :DIRECT-SLOTS (LIST (LIST ':NAME 'X) (LIST ':NAME 'Y))))

Defstruct vs Defclass: a 2x difference

I created a million instances of each (the structure spoint, and the class point), with randomized members, and the former took about 50 milliseconds, while the latter took about 100 milliseconds. Without obsessing over absolute numbers (this is a reasonable recent linux box), I believe the takeaway is that you should avoid used heavy CLOS until you really need to.

CL-USER> (defstruct spoint xp yp)
SPOINT
CL-USER> (time
(dotimes (i 1000000)
(make-spoint :xp (random 1000000) :yp (random 1000000))))
Evaluation took:
0.054 seconds of real time
0.050000 seconds of total run time (0.050000 user, 0.000000 system)
92.59% CPU
172,978,648 processor cycles
31,981,568 bytes consed

CL-USER> (defclass point () ((xp :initarg :xp) (yp :initarg :yp)))
#<STANDARD-CLASS POINT>
CL-USER> (time
(dotimes (i 1000000)
(make-instance 'point :xp (random 1000000) :yp (random 1000000))))
Evaluation took:
0.102 seconds of real time
0.100000 seconds of total run time (0.100000 user, 0.000000 system)
[ Run times consist of 0.020 seconds GC time, and 0.080 seconds non-GC time. ]
98.04% CPU
16 lambdas converted
324,534,044 processor cycles
64,606,960 bytes consed

Update: These figures are from SBCL, but I tried the same on AllegroCL and got identical results.

Of course the other takeaway is that everything is really really fast.

So much for the AllegroCL trial

I suppose it’s worth learning anyway, it seems to give a very precise control over compilation, has a bunch of libraries and is very well documented. Also, an email to support@franz.com, which turned out to be a very silly question, was answered promptly. One day, I’m sure I will buy the Professional version!

However, I can’t always use this as an experimental Common Lisp platform. Today I wanted to try out Genworks, but when I tried to load it, I saw

Error:
An explicit gc call caused tenuring and a need for 786432 more bytes of heap.
This request cannot be satisfied because you have hit the Allegro CL Free Express heap limit.
The Student Edition has an unlimited heap.
For more information on the Student Edition, see http://www.franz.com/downloads/student.lhtml.
For an evaluation of our Enterprise or Professional Editions please contact us at sales@franz.com or (510) 452-2000.
    [condition type: STORAGE-CONDITION]

I don’t want to pretend to be a student, so … back to SBCL!

AllegroGraph: Getting Started

I’m following along with Mark Watson’s excellent book on using AllegroGraph, but the automated install mentioned at the beginning didn’t work for me.

While I figure this out, the following manual version does work:

Install the server

  • Download and extract the tar.gz file

  • ./agraph-4.13.1/install-agraph ~/Lisp/AllegroGraph

  • ./AllegroGraph/bin/agraph-control --config AllegroGraph/lib/agraph.cfg start

Add a test user

(say user:test, password:xyzzy)

Install the client

  • Download and extract the tar.gz file

  • :ld $home/Lisp/agraph-4.13.1-linux86-acl90-client-lisp-acl9.0/agraph4.fasl

  • (in-package :db.agraph.user)

  • (create-triple-store "tmp-rdfstore-1"
    :user "test"
    :password "xyzzy")

Note: the example from the book uses /ns/name, but this is not allowed

  • (enable-!-reader)

Note: the book omits this at the beginning, but this is essential to do what comes next (without this, something like !owl is treated like a package name)

  • (add-triple !owl:cat !owl:eats !owl:fish)

(get-triple-by-id 1)
<cat eats fish>

Enjoy! More to follow, in fits and starts …

Lisp Books

This is something I’ve always pieced together bit-by-bit, and I’m sure a lot of other people have done the same by combining occasional blog posts, reviews on Amazon, perhaps a few mailing lists, and so on.

Adam Tornhill has reviewed a bunch of these, and I’ve read them and agree with most of them, so here is an index to some of them:

(My own current path is slightly different, btw. I had read SICP many years ago and definitely need to re-read it, but I started with Conrad Barski’s “Land of Lisp” and am now slowly working through Graham’s “ANSI Common Lisp”, hoping to move on to PAIP once I’m done)

Getting Started on OSX

Here’s what I did, though perhaps a better order of steps exists:

  • Downloaded Emacs for OSX

  • Downloaded ClozureCL from the Mac App Store.

  • Downloaded Quicklisp

  • Ran ClozureCL, then “File -> Load File …”, and selected quicklisp.lisp downloaded earlier.

  • Ran (quicklisp-quickstart:install)

  • Ran (ql:add-to-init-file) to make sure I don’t have to repeat this step again

  • Ran (ql:quickload :quicklisp-slime-helper). This downloaded SLIME and told me what to add to my .emacs:

`(load (expand-file-name “~/quicklisp/slime-helper.el”))`

  • Made a useful symlink:

  `ln -s /Applications/Clozure CL.app/Contents/MacOS/dx86cl64 ~/bin/ccl`

  • Added a reference to this in my .emacs:

`(setq inferior-lisp-program “~/bin/ccl”)`

  • Ran emacs, M-x slime works !

(or as the prompt says, “Happy hacking!”)

 

The Eric Naggum archive

I was too young to participate in these discussions when they happened, but it is particularly enlightening (IMHO) to comb through the “Erich Naggum archive”. Sure, there is some of what we might today consider “flaming”, but there are also several insights that are easily lost if not seen for what they are.

Here is an example from the comp.lang.lisp archives.

In Lisp, the fundamental programming concept is the ‘symbolic expression’, or ‘s-expression’ for short.

A s-expression is either an atom or a list of s-expressions. An object of any type except list is called an `atom’. A list whose the first atom is a symbol is called a form, and that symbol defines the meaning of the whole form.

A Lisp program is made up of many, nested forms. The Lisp type system has a large number of types in addition to symbols and lists, both atomic and containers, including numbers of many types, vectors, arrays, and strings, all of which form a type hierarchy.

Lisp has functions that work on objects at any level of this hierarchy. Despite the importance of the list for s-expressions, modern Lisp programs use lists sparingly at run-time. The s-expression is a convenient way to represent code (functions) as objects in the language itself.

It follows that most types can be represented in text form and that they can be printed from a Lisp system. This is often referred to as “code and data are interchangeable in Lisp”, but this applies to the uncompiled form of the code, only.

Lisp is naturally a compiled language, even though it also follows from the above that it is easy to write an interpreter. Toy Lisps are frequently interpreted-only. Unfortunately, most beginners only play with the toy Lisps — many a myth has thus been perpetuated.