lisp – Parerga und Paralipomena http://www.michelepasin.org/blog At the core of all well-founded belief lies belief that is unfounded - Wittgenstein Wed, 10 Oct 2012 14:59:57 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.11 13825966 Composing at the metalevel http://www.michelepasin.org/blog/2012/03/09/composing-at-the-metalevel/ http://www.michelepasin.org/blog/2012/03/09/composing-at-the-metalevel/#comments Fri, 09 Mar 2012 12:20:17 +0000 http://www.michelepasin.org/blog/?p=1109 I’ve started reading “Notes from the Metalevel: An Introduction to Computer Composition“, by Heinrich Taube, and realised I should have done that a long time ago!

Notes From the Metalevel is a practical introduction to computer composition. It is primarily intended for student composers interested in learning how computation can provide them with a new paradigm for musical composition.

I happened to have a pdf version of the book, but the good news is that there’s an html version of it too, which includes also all the midi files of the numerous examples included in the book. So make sure you check that out, if you’re interested in computer-based composition. You might also be interested in this review on computer music journal, and this course materials from Taube’s class at Illinois.

The preface to the fist chapter contains this suggestive excerpt from Leonard Schlain’s book, The Alphabet Versus the Goddess, which Taube (page 19-20) uses as a metaphor of what algorithmic composition (i.e., metalevel composition) is::

The one crowded space in Father Perry’s house was his bookshelves. I gradually came to understand that the marks on the pages were trapped words. Anyone could learn to decipher the symbols and turn the trapped words loose again into speech. The ink of the print trapped the thoughts; they could no more get away than a doomboo could get out of a pit. When the full realization of what this meant flooded over me, I experienced the same thrill and amazement as when I had my first glimpse of the bright lights of Konakry. I shivered with the intensity of my desire to learn to do this wondrous thing myself.
(spoken by Prince Modupe, a west African prince who learned to read as an adult)

It is impossible to know exactly how Prince Modupe felt when he discovered a process by which his very thoughts could be trapped and released at will again into speech. But I think his epiphany must be close to what I experienced when, as a young composer, I was first shown how I could use a computer to represent my musical ideas and then “release them” into musical compositions.
At that instant it became clear to me that there was an entire level of notation above the scores that I had been writing in my regular composition classes, a level I knew nothing about! But I could see that in this level it was possible to notate my compositional ideas in a precise manner and work with them in an almost physical way, as “trapped words” that could be unleashed into musical sound whenever I wanted.

So what does it meant to compose at the meta level?

Given the existence of the acoustic and score representations one might ask if there is yet another representation that constitutes a level of abstraction above the performance score? The answer, of course, is yes; it is what this book terms the metalevel. If the score represents the composition then the metalevel represents the composition of the composition. A metalevel representation of music is concerned with representing the activity, or process, of musical composition as opposed to its artifact, or score.

This book is about using the computer to instantiate this level: to define, model and represent the compositional processes, formalism and structures that are articulated in a musical score and acoustic performance but are not literally represented there. By using a computer the composer can work with an explicit metalevel notation, or language, that makes the metalevel as tangible as the performance and acoustic levels.

 

]]>
http://www.michelepasin.org/blog/2012/03/09/composing-at-the-metalevel/feed/ 1 1109
RDF programming with AllegroCL and AllegroGraph http://www.michelepasin.org/blog/2011/04/14/allegro-cl-graph/ Thu, 14 Apr 2011 14:19:46 +0000 http://www.michelepasin.org/blog/?p=1274 Allegro Common Lisp (wikipedia) is a commercial implementation of the Common Lisp programming language developed by Franz Inc. Allegro CL provides the full ANSI Common Lisp standard – but more interestingly for me, it also provides a very comprehensive suite of tools for semantic web programming. So I decided to give it a go, in what follows I just put together some notes on how to get started quickly.

Franz Inc. offers a whole bunch of semantic technologies, including:

  • AllegroCL: a Common Lisp implementation (homepage | install | faq | documentation) described as the “most powerful dynamic object-oriented development system available today“. It runs on all major operating systems, and it includes a cross-platform GUI too (which is not always the case for Lisp implementations!).
  • AllegroGraph: (home | docs | install) this is a high-performance, persistent RDF triplestore. It allegedly can “scale to billions of triples while maintaining superior performance” and supports SPARQL, RDFS++, and Prolog reasoning from numerous client applications (python too, as discussed in a previous post).
  • AllegroCache: (home | docs | install) this is a dynamic object caching database system. It allows programmers to work directly with objects as if they were in memory while in fact the object data is always stored persistently. It supports a full transaction model with long and short transactions, and meets the classic ACID requirements for a reliable and robust database.
  • Gruff: (home | docs | install) is an rdf graphical browser that attempts to make data retrieval more pleasant and powerful with a variety of tools for laying out cyclical graphs, displaying tables of properties, managing queries, and building queries as visual diagrams (btw thanks to Matteo for mentioning Gruff to me!)
  • Installing AllegroCL

    The good news is that if you follow the installation instructions for AllegroCL, this will include also AllegroGraph and AllegroCache. Long story short, I was able to get started with this environment surprisingly quickly. The installation on OSX involves only two steps (after filling out a form): getting the GTK+ framework (a cross-platform graphical toolkit) and then downloading the Lisp image. Double-click, install, and et-voila’ you’re done with it.

    Here’s how the Lisp IDE looks like:

    Screen shot 2011 04 14 at 13 46 49

    The IDE includes also an integrated patches-loading tool, which you should run straightaway to get the latest versions of several libraries needed by AllegroCL (wonder whether it’s that easy to install all the standard Lisp packages too..):

    Screen shot 2011 04 14 at 13 31 43

    Finally, in order to run AllegroGraph too it’s necessary to invoke an update command manually, which is easily done:

    CG-USER(3): (SYSTEM.UPDATE:INSTALL-ALLEGROGRAPH)
    Checking available AllegroGraph versions...
    Making temporary directory (/tmp/tempa18825120705a/)
    Retrieving agraph-3.3-acl8.2-macosx86.tgz into temporary directory
    Extracting tar archive /tmp/tempa18825120705a/agraph-3.3-acl8.2-macosx86.tgz
    Installing /Applications/AllegroCL/code/agraph.fasl
    Installing /Applications/AllegroCL/agraph/
    
    *********************
    
    To use the newly downloaded AllegroGraph you can load it by
    evaluating the following forms:
    
      (REQUIRE :AGRAPH)
    
    Ancillary files are located in ``/Applications//AllegroCL/agraph/''.
    

    Installing Gruff

    I also downloaded Gruff and ran it. Again, on OSx the whole process was very very straightforward. I loaded up an ontology stored in an RDF/XML file and here’s the result:

    Screen shot 2011 04 14 at 14 18 56

    Very very impressive – that’s my conclusion. Gruff offers plenty of features for viewing and also editing the rdf graph (check out the video tutorials on the homepage); with a little practice, I think it wouldn’t be that difficult to use it for creating rdf models by hand (eg as an alternative to tools like Protege). The main advantage in my view is that it’s highly interactive: being able to switch very quickly from a graph-view to a tabular one is extremely practical when inspecting or creating an rdf model.

    Time to write some code

    Haven’t been writing Lisp in a while, but since we’ve got till here it would be a shame not to get our hands dirty a little, right?

  • Tip: a nice folk named Mark Watson has written a couple of books that show how to use Allegro Graph, and he’s making them available for free on his website (thanks!). Check them out: Practical Semantic Web and Linked Data Applications, Common Lisp Edition, and Practical Semantic Web and Linked Data Applications, Java, Scala, Clojure, and JRuby Edition
  • I had a quick look at the first book mentioned (“Practical Semantic Web and Linked Data Applications, Common Lisp Edition“), and tried to follow the examples presented. Here’s the result..

    First, let’s load up AllegroGraph from AllegroCL and set up a Lisp reader macro (named ‘!’) that makes it easier to enter URIs and literals:

    CG-USER(2): (REQUIRE :AGRAPH)
    ; Fast loading /Applications/AllegroCL/code/AGRAPH.fasl
    ;   Fast loading
    ;      /Applications/AllegroCL/code/acache-2.1.12.fasl
    AllegroCache version 2.1.12
    ;     Fast loading /Applications/AllegroCL/code/SAX.001
    ;;; Installing sax patch, version 1.
    ;       Fast loading from bundle code/ef-e-anynl.fasl.
    ;         Fast loading from bundle code/ef-e-crlf.fasl.
    ;         Fast loading from bundle code/ef-e-cr.fasl.
    ;   Fast loading from bundle code/streamp.fasl.
    ;   Fast loading /Applications/AllegroCL/code/ACLRPC.fasl
    Loaded patch file /Applications/AllegroCL/update/pim001.001.
    ;   Fast loading /Applications/AllegroCL/code/PROLOG.001
    ;;; Installing prolog patch, version 1.
    ;   Fast loading /Applications/AllegroCL/code/DATETIME.001
    ;;; Installing datetime patch, version 1.
    ;   Fast loading /Applications/AllegroCL/code/streamc.002
    ;;; Installing streamc patch, version 2.
    ;     Fast loading from bundle code/efft-utf8-base.fasl.
    ;     Fast loading from bundle code/efft-void.fasl.
    ;     Fast loading from bundle code/efft-latin1-base.fasl.
    ;   Fast loading from bundle code/streamm.fasl.
    ;   Fast loading from bundle code/ef-e-crcrlf.fasl.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio001.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio002.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio003.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio004.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio005.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio006.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio007.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio008.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio009.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio010.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio011.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio012.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio013.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio014.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio015.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio016.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio017.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio018.001.
    Loaded patch file /Applications/AllegroCL/update/agraph/3.3/pio019.001.
    AllegroGraph Lisp Edition 3.3 [built on February 17, 2010 13:53:35 GMT-0800]
    Copyright (c) 2005-2010 Franz Inc.  All Rights Reserved.
    AllegroGraph contains patent-pending technology.
    With patches: io001, io002, io003, io004, io005, io996, io007, io008, io009, io010, io011, io012, io013, io014, io015, io016, io017, io018, io019.
    T
    CG-USER(3): (in-package :db.agraph.user)
    #<The DB.AGRAPH.USER package>
    TRIPLE-STORE-USER(4): (enable-!-reader)
    #<Function READ-TOKEN>
    T
    TRIPLE-STORE-USER(5): (enable-print-decoded t)
    T
    TRIPLE-STORE-USER(6): (triple-store:display-namespaces)
    rdfs => http://www.w3.org/2000/01/rdf-schema#
    err => http://www.w3.org/2005/xqt-errors#
    fn => http://www.w3.org/2005/xpath-functions#
    rdf => http://www.w3.org/1999/02/22-rdf-syntax-ns#
    xs => http://www.w3.org/2001/XMLSchema#
    xsd => http://www.w3.org/2001/XMLSchema#
    owl => http://www.w3.org/2002/07/owl#
    TRIPLE-STORE-USER(9): !rdfs:class
    !rdfs:class
    

    Next thing, we want to create a local triplestore, register a dummy namespace and add a couple of triples to it. Finally, we dump the whole triplestore in a file.

    TRIPLE-STORE-USER(10): (triple-store:create-triple-store "~/tmp/rdfstore_1")
    #<DB.AGRAPH::TRIPLE-DB /Users/mac/tmp/rdfstore_1, open @ #x21dfc80a>
    TRIPLE-STORE-USER(11): (register-namespace "kb" "http://michelepasin.org/rdfs#")
    "http://michelepasin.org/rdfs#"
    TRIPLE-STORE-USER(12): (triple-store:display-namespaces)
    rdfs => http://www.w3.org/2000/01/rdf-schema#
    err => http://www.w3.org/2005/xqt-errors#
    fn => http://www.w3.org/2005/xpath-functions#
    rdf => http://www.w3.org/1999/02/22-rdf-syntax-ns#
    xs => http://www.w3.org/2001/XMLSchema#
    xsd => http://www.w3.org/2001/XMLSchema#
    owl => http://www.w3.org/2002/07/owl#
    kb => http://michelepasin.org/rdfs#
    TRIPLE-STORE-USER(13): (defvar *doc1* (resource "http://www.michelepasin.org/research/"))
    *DOC1*
    TRIPLE-STORE-USER(14): *doc1*
    !<http://www.michelepasin.org/research/>
    TRIPLE-STORE-USER(15): (triple-store:add-triple *doc1* !rdf:type !kb:article)
    1
    TRIPLE-STORE-USER(16): (triple-store:add-triple *doc1* !rdf:comment !"what a wonderful book")
    2
    TRIPLE-STORE-USER(17): (triple-store:get-triples-list)
    (< type article> < comment what a wonderful book>)
    NIL
    TRIPLE-STORE-USER(18): (print-triples (triple-store:get-triples-list))
    <http://www.michelepasin.org/research/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://michelepasin.org/rdfs#article> .
    <http://www.michelepasin.org/research/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#comment> "what a wonderful book" .
    TRIPLE-STORE-USER(19): (with-open-file (output "~/tmp/testoutput" :direction :output :if-does-not-exist :create)
    (print-triples (triple-store:get-triples-list) :stream output :format :ntriple))
    

    If we open the contents of the newly created “~/tmp/testoutput” file, here’s what we would find:

    <http://www.michelepasin.org/research/>
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> 
            <http://michelepasin.org/rdfs#article> .
    <http://www.michelepasin.org/research/>
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#comment> 
            "what a wonderful book" .
    

    Finally, let’s use SPARQL to launch a (quite dumb) query that retrieves all triples from the triplestore :

    TRIPLE-STORE-USER(53): (sparql:run-sparql 
     " PREFIX kb: <http://www.michelepasin.org/research#> 
       SELECT ?article_uri ?pred ?obj WHERE {
       ?article_uri ?pred ?obj . 
       }"
     )
    <?xml version="1.0"?>
    <!-- Generated by AllegroGraph 3.3 -->
    <sparql xmlns="http://www.w3.org/2005/sparql-results#">
      <head>
        <variable name="article_uri"/>
        <variable name="pred"/>
        <variable name="obj"/>
      </head>
      <results>
        <result>
          <binding name="article_uri">
            <uri>http://www.michelepasin.org/research/</uri>
          </binding>
          <binding name="pred">
            <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri>
          </binding>
          <binding name="obj">
            <uri>http://michelepasin.org/rdfs#article</uri>
          </binding>
        </result>
        <result>
          <binding name="article_uri">
            <uri>http://www.michelepasin.org/research/</uri>
          </binding>
          <binding name="pred">
            <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#comment</uri>
          </binding>
          <binding name="obj">
            <literal>what a wonderful book</literal>
          </binding>
        </result>
      </results>
    </sparql>
    T
    :SELECT
    (|?article_uri| |?pred| |?obj|)
    TRIPLE-STORE-USER(54):
    

    That’s all for now; this is enough to get started with Allegro-CL and the semantic web programming libraries it contains.

    Mind that I’ve only scratched the surface here, there’s lots and lots more that can be done with this environment. If you want to explore these topics further make sure you have a look at Watson’s book, ’cause that’s a great (and free) resource, really!

     

    ]]>
    1274
    Clojure or not clojure? http://www.michelepasin.org/blog/2010/11/25/clojure-or-not-clojure/ http://www.michelepasin.org/blog/2010/11/25/clojure-or-not-clojure/#comments Thu, 25 Nov 2010 15:06:35 +0000 http://www.michelepasin.org/blog/?p=1024 Clojure is a quite recent programming language that’s becoming popular among developers; the big selling point is that it’s functional and dynamically typed (such as Lisp or Python), but since it uses Java’s Virtual Runtime as its platform it also accommodates the needs of the many developers have been growing up in the Java world.

    The book Programming Clojure sums up well the pros of this language:

    Clojure is elegant. Clojure’s clean, careful design lets you write programs that get right to the essence of a problem, without a lot of clutter and ceremony.
    Clojure is Lisp reloaded. Clojure has the power inherent in Lisp, but is not constrained by the history of Lisp.
    Clojure is a functional language. Data structures are immutable, and functions tend to be side-effect free. This makes it easier to write correct programs, and to compose large programs from smaller ones.
    Clojure is concurrent. Rather than error-prone locking, Clojure provides software transactional memory.
    Clojure embraces Java. Calling from Clojure to Java is direct, and goes through no translation layer.
    Clojure is fast. Wherever you need it, you can get the exact same performance that you could get from hand-written Java code.

    I’ve been programming in Lisp for a while, then moved to Python in order to use something less dated and to be able to do more agile web development. But the strengths of Lisp, together with that kind of magic that comes with it (maybe coming from the code-as-data paradigm) is something which I bet all Lisp programmers miss in other languages. So I decided to give Clojure a go..

    Installation is surprisingly super easy – and I mean it – especially if you are on mac osX. Clojure is a java library, so all you have to do is download the package and run it from the command line using your java compiler. That gives you the basic interactive environment:

    
    java -cp clojure.jar clojure.main

    The interpreter is good for testing, but not for building large programs. So the next step is getting an IDE. Looks like there are many choices available, so just pick one of your liking. I personally love TextMate a lot, so I was happy to find out that there is a clojure bundle that contains all that you need to get started (yes, the clojure environment too, so you can even skip the step above). Easy beasy to install, but first you need to install Cake, a build tool that you can get via ruby’s gem command (usually preinstalled on OSx). So:

    
    sudo gem install cake

    Then install Textmate’s bundle for clojure like this:

    
    $ cd ~/Library/Application Support/TextMate/Bundles
    $ git clone git://github.com/swannodette/textmate-clojure.git Clojure.tmbundle
    $ osascript -e 'tell app "TextMate" to reload bundles'

    I don’t use Ruby, so the final step for me was adding to the system path the location of ruby’s gems (so that Cake can be run from Textmate). Open up you ~/.bash_profile and add this line:

    
    export PATH="/Users/mike/.gem/ruby/1.8/bin:$PATH"

    That’s it! A nice fellow created a really good video tutorial about how to use Textmate with the Clojure bundle, so I was able to run my first application quite quickly:

    Once you’ve familiarized with the environment, copy and paste the code below – it’s an implementation of the Tetris game in clojure (which I found here). Very useful as a learning resource!

    (ns tetris
      (:import
        (javax.swing JFrame)
        (java.awt Canvas Graphics Color Toolkit)
        (java.awt.event ActionListener KeyListener KeyEvent))
      (:gen-class))
    
    (def *cols* 10)
    (def *rows* 20)
    (def *width* 300)
    (def *height* 600)
    (def *offset* (atom [0, 0]))
    (def *rotation* (atom nil))
    (def *shapes*  [[[0,1],[0,2],[0,3],[0,4]]
                    [[0,0],[0,1],[1,1],[1,2]]
                    [[1,2],[1,1],[0,1],[0,0]]
                    [[0,0],[0,1],[1,0],[1,1]]
                    [[0,0],[0,1],[0,2],[1,2]]
                    [[1,0],[1,1],[1,2],[0,2]]])
    
    (defn get-shape []
      (let [shape (rand-nth *shapes*)
            offset (inc (rand-int (- *cols* 3)))]
        (map (fn [[x y]] [(+ x offset), y]) shape)))
    
    (defn get-board []
      (vec (range (* *rows* *cols*))))
    
    (defn pos-to-xy [pos]
      (let [x (mod pos *cols*)
            y (int (/ (- pos x) *cols*))]
        [x, y]))
    
    (defn collides?
      ([board x y pos]
        (let [[posx posy] (pos-to-xy pos)]
          (and
            (> x (- 1))
            (< x *cols*)
            (< y *rows*)
            (not (and
                  (= posx x)
                  (= posy y)
                  (not (get board (+ pos *cols*))))))))
      ([board shape pos]
        (every?
          #{true}
          (for [[x y] shape]
           (collides? board x y pos))))
      ([board shape]
        (not (reduce
               #(and %1 (collides? board shape %2))
              (range (count board)))) ))
    
    (defn rotate [board shape]
      (if (nil? @*rotation*)
        shape
        (let [[avg-x avg-y] (->> shape
                              (reduce
                                (fn [[tx ty] [x y]]
                                  [(+ tx x), (+ ty y)]))
                              (map #(int (/ % 4))))
    
              rotated (map (fn [[x y]]
                             [(int (+ avg-x (- y avg-y)))
                              (int (- avg-y (- x avg-x)))])
                        shape)]
          (if (collides? board rotated)
            shape rotated))))
    
    (defn shift [board shape]
      (let [shifted (map
                      (fn [[x y]]
                        [(+ x (first @*offset*)), y])
                      shape)]
        (if (collides? board shifted)
          shape shifted)))
    
    (defn transform [board shape drop?]
      (let [shifted (shift board shape)
            rotated (rotate board shifted)]
        (if drop?
          (map (fn [[x y]]
                 [x, (if drop? (inc y) y)]) rotated)
          rotated)))
    
    (defn clear-lines [board]
      (let [new-board (apply concat
                        (filter #(some #{true} %)
                          (partition *cols* board)))]
        (into
          (vec (map (fn [_] true)
                 (range (- (count board) (count new-board)))))
          new-board)))
    
    (defn update-board [board shape]
      (vec (map #(let [[x y] (pos-to-xy %)]
                   (if (some
                         (fn [[px py]] (and(= x px) (= y py)))
                         shape)
                     false (get board %)))
             (range (count board)))))
    
    (defn game-over? [board]
      (not (reduce #(and %1 %2)
             (butlast (rest (take *cols* board))))))
    
    ;;;;;;Controls;;;;
    (def *dirs* {KeyEvent/VK_LEFT  [-1, 0]
                 KeyEvent/VK_RIGHT [1, 0]
                 KeyEvent/VK_UP :left
                 KeyEvent/VK_DOWN :right})
    
    (defn handle-input [#^KeyEvent event]
      (let [key (.getKeyCode event)]
        (cond
          (or (= key KeyEvent/VK_LEFT) (= key KeyEvent/VK_RIGHT))
          (let [disp (*dirs* key)]
            (when disp (swap! *offset* #(map + disp %))))
          (or (= key KeyEvent/VK_UP) (= key KeyEvent/VK_DOWN))
          (reset! *rotation* (*dirs* key)))))
    
    (defn input-listener []
      (proxy [ActionListener KeyListener] []
        (actionPerformed [e])
        (keyPressed [e] (handle-input e))
        (keyReleased [e])
        (keyTyped [e])))
    
    ;;;;;;;UI;;;;;;;;;
    (defn draw [#^Canvas canvas draw-fn]
      (let [buffer  (.getBufferStrategy canvas)
            g       (.getDrawGraphics buffer)]
        (try
          (draw-fn g)
    
          (finally (.dispose g)))
        (if (not (.contentsLost buffer))
          (. buffer show))
        (.. Toolkit (getDefaultToolkit) (sync))))
    
    (defn draw-square [x y #^Graphics g]
      (let [width  (/ *width* *cols*)
            height (/ *height* *rows*)
            xpos   (* x width)
            ypos   (* y width)]
        (doto g
          (.setColor Color/RED)
          (.fillRect xpos, ypos, width, height)
          )))
    
    (defn draw-game-over [#^Graphics g]
      (doto g
       (.setColor Color/BLACK)
       (.fillRect 0 0 *width* *height*)
       (.setColor Color/green)
       (.drawString "GAME OVER" (- (/ *width* 2) 50)  (/ *height* 2))))
    
    (defn draw-board [board shape]
      (fn [#^Graphics g]
        (doto g
          (.setColor Color/BLACK)
          (.fillRect 0 0 *width* *height*))
    
        (doseq [square (range (count board))]
          (when (not (get board square))
           (let [[x y] (pos-to-xy square)]
             (draw-square x y g))))
    
        (doseq [[x y] shape]
          (draw-square x y g))))
    
    (defn -main [& args]
      (let [frame  (JFrame. "Tetris")
            canvas (Canvas.)]
        (doto frame
          (.setSize *width* (+ (/ *height* *rows*) *height*))
          (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
          (.setResizable false)
          (.add canvas)
          (.setVisible true))
    
        (doto canvas
          (.createBufferStrategy 2)
          (.addKeyListener (input-listener))
          (.setVisible true)
        (.requestFocus))
    
        ;;game loop
        (loop [board    (get-board)
               shape    (get-shape)
               old-time (System/currentTimeMillis)]
    
          (reset! *offset* [0,0])
          (reset! *rotation* nil)
          (Thread/sleep 10)
          (draw canvas (draw-board board shape))
    
          (let [cur-time (System/currentTimeMillis)
                new-time (long (if (> (- cur-time old-time) 150)
                                 cur-time
                                 old-time))
                drop?    (> new-time old-time)]
            (cond
              (game-over? board)
              (draw canvas draw-game-over)
    
              (collides? board shape)
              (recur (update-board board shape)
                (get-shape)
              new-time)
    
              :default
              (recur
                (clear-lines board)
                (transform board shape drop?)
                new-time)
              )))))
    (-main)
    

    Quite amazing isn’it?
    However, the very next question for me was, why investing time and money into this new language? It’s definitely interesting, but does it compare to python and django (for example) when it comes to build social web apps? Can’t really answer to these questions at the moment, but I found really useful the conclusions of an article I found online (on Java News Brief):

    • Are you looking for a way to make concurrent programming easier?
    • Are you open to branching outside the world of object-oriented programming to try functional programming?
    • Is it important for the applications you write to run on the JVM in order to take advantage of existing Java libraries, portability and other benefits?
    • Do you prefer dynamically-typed languages over statically-typed ones?
    • Do you find the minimal, consistent syntax of Lisp dialects appealing?
    If you answered “yes” some of these questions then you should consider using Clojure as your next programming language.

    Finally, a couple of other useful learning resources:

    setting up clojure on mac osX Leopard
    clojure for lisp programmers (video lecture)
    Clojure Tutorial For the Non-Lisp Programmer
    – a clojure implementation of the snake game

    ]]>
    http://www.michelepasin.org/blog/2010/11/25/clojure-or-not-clojure/feed/ 2 1024
    Scheme and Lisp http://www.michelepasin.org/blog/2010/11/08/scheme-and-lisp/ Mon, 08 Nov 2010 12:57:13 +0000 http://www.michelepasin.org/blog/?p=866 If you’re coming from Lisp, and then start using Scheme (or the other way around) there are a few small differences between the two languages that it’s useful to always keep in mind. I tried to do that a number of times, but inevitably I find myself once again wondering: how do you say ‘progn’ in scheme?

    So, since I recently found online a succinct table that sums up the differences, I thought I’d pass it on to posterity here too.

    Screen shot 2010-11-08 at 14.29.12.png

    By the way, on the same site the authors report of a small scheme library (initdr.scm) that implements a few very common Lisp functions. Including [dotimes dolist intersection, union set-difference copy-list subset every some copy-tree subst sublis nconc nreverse]… Quite useful too!

    UPDATE 28/11/10:

    I realized that most of these lisp functions are already available in Impromptu, under the cl: namespace (check out the common-lisp library functions section on the wiki). Below are just a couple of additions to that, based on the initdr.scm library I was mentioning.. apologies for the confusion!

    ;;;;;;;;;;;;;;;;
    ;;; LISP ADDITIONS 
    ;; the rest of this is in the cl: impromptu library
    ;;;;;;;;;;;;;;;;
    
    
    (define cl:first car)
    (define cl:rest cdr)
    (define cl:count length)
    
    ;; reverse of cons: (cons 'b '(a))
    (define cl:l-put
       (lambda (obj lst)
          (reverse (cons obj (reverse lst)))))
    
    ;; dont know why but I like it reversed..
    (define cl:nth (lambda (x lst)
                   (list-ref lst x)))
    
    
    (define (1+ n) (+ n 1))
    (define (1- n) (- n 1))
    
    
    ;; (subst 9 7 '(5 (5 6 7(6 7))))    =>  (5 (5 6 9 (6 9)))      
    (define (cl:subst new old tree)
      (if (pair? tree)
          (let ((left (subst new old (car tree)))
                (right (subst new old (cdr tree))))
            (if (and (eq? left (car tree))
                     (eq? right (cdr tree)))
                tree
                (cons left right)))
          (if (eqv? old tree)
              new
              tree)))
    
    
    
    ;; (sublis '((6 . 9) (7 . 10)) '(5 (5 6 7 (6 7)))))  => (5 (5 9 10 (9 10)))
    (define (cl:sublis alist tree)
      (if (pair? tree)
          (let ((left (sublis alist (car tree)))
                (right (sublis alist (cdr tree))))
            (if (and (eq? left (car tree))
                     (eq? right (cdr tree)))
                tree
                (cons left right)))
          (let ((new (assv tree alist)))
            (if new
                (cdr new)
                tree) ) ) )
    
    
    ;; (copy-tree '(5 (5 6 7(6 7))))
    (define (cl:copy-tree x)
      (if (pair? x)
          (cons (copy-tree (car x))
                (copy-tree (cdr x)))
          x))
    
    
    ; Convert a floating-point number to a string of sign and at most 4 characters.
    ; Rounds the number so that 1.999 will come out as 2.00 , very small as 0.0 .
    ; numstring is written assuming that num is not too large or too small,
    ; i.e. num must be printable in 4 digits.
    (define (cl:numstring num)
      (let* ((numc (abs num)) (sign (if (< num 0) -1 1)) (exponent 0))
        (if (< numc 1.0e-6)
        "0.0"
        (begin
          (if (< numc 1.0)
              (begin (while (< numc 100)
                    (set! numc (* numc 10))
                    (set! exponent (1- exponent)))
                 (set! numc (* (round numc) (expt 10 exponent))) )
              (set! numc (* numc 1.0001)))
          (if (< sign 0)
              (string-append "-"
                     (substring (number->string numc) 0
                       (min 4 (string-length (number->string numc)))))
              (substring (number->string numc) 0
                 (min 4 (string-length (number->string numc))))) ) ) ))
    
    
    
    
    ;(list-flatten '(9 9 (9 9 9 ))))  = (9 9 9 9 9)
    
    (define cl:list-flatten 
       (lambda (l)
          (cond ((null? l)
                 '())
                ((atom? l)
                 (list l))
                (#t (append (cl:list-flatten  (car l)) (cl:list-flatten  (cdr l)))))))
    
    ]]>
    866
    A video that may convince you that LISPers are a bit crazy http://www.michelepasin.org/blog/2010/10/29/a-video-that-may-convince-you-that-lispers-are-a-bit-crazy/ Fri, 29 Oct 2010 14:25:26 +0000 http://www.michelepasin.org/blog/?p=860 Actually it’s not just a video, there’s a book too:

    Land of Lisp, Learn to Program in Lisp, One Game at a Time! by Conrad Barski, M.D.

    ]]>
    860
    AJAX in Lisp with JQuery http://www.michelepasin.org/blog/2008/02/27/ajax-in-lisp-with-jquery/ Wed, 27 Feb 2008 18:14:30 +0000 http://people.kmi.open.ac.uk/mikele/blog/?p=271 I was asked to give an example of lisp+ajax, so once I prepared it I thought it could be of help to other people too :-)

    First of all, I am not a professional lisper at all, just got to know it a little during the last two years. The code I’m presenting here might not be the best one, but it works and essentially shows you how to do cool ajax stuff by using lisp [btw, some of this code comes from somebody who knows about lisp much more than I do, this guy here].

    Anyways, let’s get going: we want to create a very very simple webapp that changes the color of some text in the page, using an ajax call. So we’ll have one main page, another page which gives back the code for updating the main page through ajax, and a couple of js files we want to use for the front-end functionality (among them, the fantastic jquery).

    First of all, we’ll need two handy packages for setting up a fully-working lisp server: hunchentoot and cl-who (the more you learn about these packages, the better it is – and go through the examples – they’re really useful!). Once you’ve installed them, using asdf-install or whatever-you-like, let’s load them up and set a couple of environment variables.

    (asdf:operate 'asdf:load-op :hunchentoot)
    (asdf:operate 'asdf:load-op :cl-who)
    
    (use-package :cl-who)
    (setq hunchentoot:*catch-errors-p* nil
    hunchentoot:*log-lisp-backtraces-p* t)

    Then we define a couple of functions for starting/stopping the server and setting up the dispatcher table, which is where the mapping between web-pages in the application and lisp functions in the backend is specified. We’ll have three of these mappings: one for the main page, one for the page that serves the ajax changes (what-color?), and one for passing the static files, such as js and css (static/).

    
    
    (defvar *web-server* nil)
    
    (defun start-server ()
    (setq hunchentoot:*dispatch-table*
    (nconc
    (mapcar (lambda (args)
    (apply #'hunchentoot:create-prefix-dispatcher args))
    '(("/static/" serve-static)
    ("/what-color" what-color?)
    ("/main" main)))
    (list #'hunchentoot:default-dispatcher)))
    (setf *web-server* (hunchentoot:start-server :port 3000)))
    
    (defun stop-server ()
    (hunchentoot:stop-server *web-server*))
    
    

    When the start-server function is called, it’ll load the dispatch table and start the sever on port 3000.

    The hardest thing to do now, before creating the functions that output the web-pages, is to set up the functions that handle the static files. First of all define your location, so that lisp knows where the root folder of the webapp is. That’s how it looks on my mac – you probably want to change that according to needs.

    
    
    (defvar *location* "/Users/myname/dev-try/hunchentoot-examples/")
    
    

    Then the function for serving the static files (serve-static). In this example web-app we’ll only have two of them (see below), but you might want to have more (e.g. css, jpg etc..). The other three functions below basically retrieve the static file, check its mime-type and pass it back to the dispatcher.

    
    
    (defun serve-static ()
    (let* ((uri (hunchentoot:request-uri))
    (file (subseq uri (length "/static/"))))
    (format *error-output* "serve-static: file=~S~%" file)
    (http-write-file file (mime-types file))))
    
    (defun http-write-file (filename mime-type)
    "Send contents of FILENAME to the HTTP stream, along with its MIME-TYPE."
    (setf (hunchentoot:content-type) mime-type)
    (let* ((stream (hunchentoot:send-headers))
    (buffer (make-array 1024 :element-type '(unsigned-byte 8 )))
    (local-filename (format nil "~astatic/~a" *location* filename)))
    (with-open-file (in local-filename :element-type '(unsigned-byte 8 ))
    (loop for pos = (read-sequence buffer in)
    until (zerop pos)
    do (write-sequence buffer stream :end pos)))))
    
    (defun mime-types (filename)
    (let ((ext (subseq filename (+ 1 (position #. filename :from-end t)))))
    (second (assoc ext '(("txt" "text/plain")
    ("css" "text/css")
    ("lisp" "text/plain")
    ("html" "text/html")
    ("js" "text/javascript")
    ("png" "image/png"))
    :test #'string=))))
    
    (defun write-http-stream (mime-type payload)
    (setf (hunchentoot:content-type) mime-type)
    (write-sequence payload (hunchentoot:send-headers)))
    
    

    That was the trickiest part. Now let’s just create the functions that produce the html code to be passed to the browser/javascript. Before that, just a couple of useful macros that wrap the standard cl-who functions. With-html for creating html code without a header, and with-html-top for creating also the header.

    
    
    (defmacro with-html (&body body)
    `(with-html-output-to-string
    (*standard-output* nil :prologue nil :indent nil)
    (htm ,@body)))
    
    (defmacro with-html-top (&body body)
    `(with-html-output-to-string
    (*standard-output* nil :prologue t :indent nil)
    ,@body))
    
    

    Finally, the pages we can call from the browser. Main creates the main page of the app, linking to the javascript files. what-color? just outputs a random color name out of a predefined list:

    
    
    (defun main ()
    (with-html-top
    (:html (:head
    (:title "Home page")
    (:script :type "text/javascript" :src "/static/jquery.pack.js")
    (:script :type "text/javascript" :src "/static/my_functions.js"))
    (:body
    (:p :id "text" "Hi there - this is the only page for now")
    (:a :href "javascript:changeColor()" "click here to change the color!")))))
    
    (defun what-color? ()
    (let ((color-list '("blue" "red" "lavender" "black" "yellow"
    "orange" "mandarin" "MistyRose" "Olive")))
    (nth (random (length color-list)) color-list)))
    
    

    That’s it really, for the backend. Now all you have to do is to create a folder called ‘static’ wherever you specified the *location* variable to point at. Inside the folder, put a copy of the latest JQuery code (jquery.pack.js), and create a new file called my_functions.js with this elementary function (sorry – that’s all the ajax we’re getting for now…) . It’s a simple function that calls the server for getting a color name, and uses it to change the color of a dom element.

    
    
    function changeColor() {
    $.get("what-color",
    function(data){
    $("#text").css("color",data);
    }
    );
    }
    
    

    Almost done. Enter (start-server) in the lisp listener, and go to http://localhost:3000/main to see your first lisp-ajax application! [if the colors don’t show properly, make sure you are using Firefox]

    Have fun!

     

    ]]>
    271
    Lisp blog engine http://www.michelepasin.org/blog/2007/09/20/lisp-blog-engine/ Thu, 20 Sep 2007 14:40:41 +0000 http://people.kmi.open.ac.uk/mikele/blog/?p=251 I’ve been very happy to help out Cyrus Harmon debugging his Nuclblog package to make it work with lispworks too (he developed it using sbcl)… it took a dozen emails to understand each other – but the result was worth it! It’s a hunchentoot-based engine that you can easily modify and adapt to your needs….

    By the way, a more profane thing: I’ve always suspected Edi Weitz (author of many lisp libraries) had a secret passion for Frank Zappa – but now there’s no mystery anymore, since a friend pointed me at one of the main sources for his creations’ funny names: Zappa’s works!

    ]]>
    251
    Lispdoc – Online Lisp Documentation Search http://www.michelepasin.org/blog/2007/05/18/lispdoc-online-lisp-documentation-search/ Fri, 18 May 2007 11:09:36 +0000 http://people.kmi.open.ac.uk/mikele/blog/?p=234 I read this inonPlanet Lisp:

    William Bland just keeps on improving lispdoc, his online Lisp documentation search utility. The utility has a lot of neat features:

     

    ]]>
    234
    New macs too new for me http://www.michelepasin.org/blog/2007/05/11/new-macs-too-new-for-me/ Fri, 11 May 2007 15:46:08 +0000 http://people.kmi.open.ac.uk/mikele/blog/?p=230

    I just got a new double processor do-it-all mac from the generous kmi, but surprise…… LISP DOESNT WORK ON IT! The link is from one year ago… i know i’m among the last ones arriving here…and especially MCL (which i keep saying is ultra-cool) is a total mystery on intel-based macs. A digitool policy?

    ]]>
    230
    What Lisp to choose, really? http://www.michelepasin.org/blog/2007/04/24/what-lisp-to-choose-really/ http://www.michelepasin.org/blog/2007/04/24/what-lisp-to-choose-really/#comments Tue, 24 Apr 2007 19:41:53 +0000 http://people.kmi.open.ac.uk/mikele/blog/?p=229 During the last days, I almost switched from Lispworks (too many tabs, too many things in general) back to MCL (essential, fast, with a powerful meta-dot command). But I run into many problems, the most important of them is getting ASDF to run, so to be able to run the server (Hunchentoot) from there. I set up the init file to load ASDF in MCL, and tried to share the same registry which I previously created through Lispworks and asdf-install…. but it doesnt want to work! Why’s that?

    …………..LISTENER
    Welcome to Macintosh Common Lisp Version 5.0!
    ? (asdf:operate ‘asdf:compile-op :asdf-install)
    > Error: Error component “asdf-install” not found
    > While executing: ASDF:FIND-SYSTEM
    > Type Command-. to abort.
    See the Restarts… menu item for further choices.
    1 > asdf:*central-registry*
    (“Macintosh HD:Users:michelepasin:Documents:Lisp:asdf-mcl-install-dir:systems:” *DEFAULT-PATHNAME-DEFAULTS*)
    1 > (asdf:operate ‘asdf:compile-op :cl-who)
    > Error: Error component “cl-who” not found
    > While executing: ASDF:FIND-SYSTEM
    > Type Command-. to abort.
    See the Restarts… menu item for further choices.
    2 >

    ……………INIT file (in MCL folder)
    #-:asdf (load “Macintosh HD:Users:michelepasin:Documents:Lisp:asdf:asdf”)

    (pushnew “Macintosh HD:Users:michelepasin:Documents:Lisp:asdf-mcl-install-dir:systems:” asdf:*central-registry* :test #’equal)

    Then later today I found out about this (basically, Digitool’s misteriosly ‘silent’ about MCL and intel-macs). So the question is: what’s the right framework to choose?

    ]]>
    http://www.michelepasin.org/blog/2007/04/24/what-lisp-to-choose-really/feed/ 1 229