Showing posts with label lisp. Show all posts
Showing posts with label lisp. Show all posts

Monday, June 07, 2010

International Lisp Conference 2010

I was asked to spread the word about the upcoming International Lisp Conference 2010 (ILC-2010). So here you have the Call for Arms Papers (from the original attachment):

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   International Lisp Conference 2010   

   October 19-21, 2010   

   John Ascuaga's Nugget (Casino)   

   Reno/Sparks, Nevada, USA (near Lake Tahoe)   

     

   Collocated with SPLASH 2010 (OOPSLA & DLS & more)   

   see also http://splashcon.org as well as

   http://www.dynamic-languages-symposium.org/dls-10/   

     

   In association with ACM SIGPLAN (PENDING)       

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Association of Lisp Users is pleased to announce that the 2010

International Lisp Conference will be held in Reno, Nevada, in

collocation with SPLASH 2010. The scope includes all areas related to

the Lisp family of programming languages.

Accepted papers will be published in the ACM Digital Library (PENDING).

Extended Abstracts and Papers must be written in English and submitted

electronically at http://www.easychair.org/conferences?conf=ilc2010 in

PDF or WORD format. If an Extended Abstract is submitted, it must be

between 2 and 4 pages, with full paper to follow before final deadline.

Final submissions must not exceed 15 pages and need to use the ACM

format, for which templates which can be found at:

   http://www.acm.org/sigs/pubs/proceed/template.html.

Important Dates:

~~~~~~~~~~~~~~~~

* Deadline for Abstract Submission: August 1, 2010

* Deadline for Paper Submission: September 6, 2010

* Author notification: September 20, 2010

* Final paper due (in electronic form): October 5, 2010

* Conference: October 19-21, 2010

Scope:

~~~~~~

Lisp is one of the greatest ideas from computer science and a major

influence for almost all programming languages and for all

sufficiently complex software applications.

The International Lisp Conference is a forum for the discussion of

Lisp and, in particular, the design, implementation and application of

any of the Lisp dialects. We encourage everyone interested in Lisp to

participate.

We invite high quality submissions in all areas involving Lisp

dialects and any other languages in the Lisp family, including, but

not limited to, ACL2, AutoLisp, Clojure, Common Lisp, ECMAScript,

Dylan, Emacs Lisp, ISLISP, Racket, Scheme, etc.

Topics may include any and all combinations of Lisp and:

* Language design and implementation

* Language critique

* Language integration, inter-operation and deployment

* Applications (especially commercial)

* 'Pearls' (of wisdom)

* Experience reports and case studies

* Reflection, meta-object protocols, meta-programming

* Domain-specific languages

* Programming paradigms and environments

* Parallel and distributed computing

* Software evolution

* Theorem proving

* Scientific computing

* Data mining

* Semantic web

We also encourage submissions about known ideas as long as they are

presented in a new setting and/or in a highly elegant way.

Authors concerned about the appropriateness of a topic may communicate

by electronic mail with the program chair prior to submission.

Each paper should explain its contributions in both general and

technical terms, identifying what has been accomplished, explaining

why it is significant, and comparing it with previous work. Authors

should strive to make their papers understandable to a broad audience.

Each paper will be judged according to its significance, novelty,

correctness, clarity, and elegance.

The official language of the conference is English. Some further

information is available at the conference web site, with more details

added later. See: http://www.international-lisp-conference.org

Technical Program:

~~~~~~~~~~~~~~~~~~

Original submissions in all areas related to the conference themes are

invited for the following categories.

* Papers: Technical papers of up to 15 pages that describe original

   results or explain known ideas in new and elegant ways, or extended

   abstracts of 4 pages soon followed by the corresponding full paper.

* Demonstrations: Abstracts of up to 4 pages for demonstrations of

   tools, libraries, and applications.

* Tutorials: Abstracts of up to 4 pages for in-depth presentations

   about topics of special interest for at least 90 minutes and up to

   180 minutes.

* Workshops: Abstracts of up to 4 pages for groups of people who

   intend to work on a focused topic for half a day.

* Panel discussions: Abstracts of up to 4 pages for discussions about

   current themes. Panel discussion proposals must mention panel

   members who are willing to partake in a discussion.

* Lightning talks: Abstracts of up to one page for talks to last for

   no more than 5 minutes.

Depending on the technical content, each submitted paper will be

classified by the program committee as either a technical paper or as

an experience paper; and authors will be informed about this

classification. Note that all interesting submissions are considered

valuable contributions to the success of the ILC series of

conferences. As in past ILC's since 2007, accepted papers in both

categories will be presented at the conference, included in the

proceedings, and submitted to the ACM digital library.

Organizing Committee:

~~~~~~~~~~~~~~~~~~~~~

* General Chair:

   JonL White - The Ginger IceCream Factory of Palo Alto, ALU

* Program Chair:

   Antonio Leitao - Instituto Superior Tecnico/INESC-ID

* Conference Treasurer:

   Duane Rettig - Franz, Inc., ALU Director

* Publicity Chair:

   Daniel Herring - ALU Director

* ALU Treasurer:

   Rusty Johnson - TASC, Inc., ALU Director

Program Committee:

~~~~~~~~~~~~~~~~~~

* Antonio Leitao - Instituto Superior Tecnico/INESC-ID, Portugal

* Alex Fukunaga - University of Tokyo, Japan

* Charlotte Herzeel - Vrije Universiteit Brussel, Belgium

* Christophe Rhodes - Goldsmiths College, University of London, UK

* Didier Verna - EPITA Research and Development Laboratory, France

* Duane Rettig - Franz, Inc., USA

* Giuseppe Attardi - University of Pisa, Italy

* Jeff Shrager - Symbolic Systems Program, Stanford University, USA

* Joe Marshall - Google, Inc., USA

* Julian Padget - University of Bath, UK

* Keith Corbett - Clozure Associates, USA

* Kent Pitman - PTC, USA

* Manuel Serrano - INRIA Sophia Antipolis, France

* Marc Feeley - University of Montreal, Canada

* Marie Beurton-Aimar University of Bordeaux 1, France

* Mark Stickel - SRI International, USA

* Matthias Felleisen - Northeastern University, USA

* Scott McKay - ITA Software, USA

Contacts:

~~~~~~~~~

* Questions: ilc10-organizing-committee at alu.org

* Program Chair: ilc2010 at easychair.org

For more information, see http://www.international-lisp-conference.org


I'm curious about when are "clojurers" going to join forces with the rest of lispers on these kind of conferences. Specially since this one is collocated with SPLASH 2010, maybe it isn't such a bad idea to start doing it now :)

Monday, May 31, 2010

Yet another Clojure + Compojure + Google App Engine post

Have I mentioned I'm kinda late to this show? Well, better late than sorry. Anyway, I think you can't have too much of these, specially in times where google application engine (GAE) is growing and so is Clojure.

The scenario was like most others: I wanted to build my webapp using GAE and clojure, and also stay on the bleeding edge of each technology. So lets see what I've got. I started by taking a look at the "literature" available as blog posts and group discussions (such as this and this).

I installed lein, and created a standard project.clj (By force of habit, forgot to use "lein new", but it's practically the same). I added the following directives on defproject:

:source-path "src"
:compile-path "war/WEB-INF/classes/"
:library-path "war/WEB-INF/lib/"
;; namespaces will trigger AOT compilation to bytecode. you want this!
:namespaces       [ginasiosunderground.servlet]
My goal is to produce a war directory, to upload to gae servers. So I told lein to compile to war/WEB-INF/classes, using war/WEB-INF/lib as a classpath dir. (More to come later on that :namespaces directory). The final project.clj is the following:


You can see the list of dependencies. I'm using the latest clojure 1.2, compojure 0.4, hiccup 0.2.4, a ring 0.2 (specifically adapted to use with gae servers) and appengine-clj (from r0man's fork). I also use clojure-json (to make my life easier on jQuery client side ajax calls). I'd like to mention the libraries from google. As of now, a default lein setup can't find those up to date versions (they are available, but I didn't want to toy around with maven repositories to make the magic happen). So I got those jars from the gae java sdk (download it from gae's site) and placed them on my war/WEB-INF/lib folder. Now be ware, you should have a copy of them somewhere else, because each lein clean you do will delete them from the lib directory! (eventually I'll get around to automate this process. I also know there's a "lein gae" plugin somewhere, but haven't tried yet, I'm not sure if it does what I want). One last thing about lein, you'll have to remove commons-fileupload-1.2.1.jar from your lib dir, otherwise gae will complain about it (it did, for me!).
Let's move on, then. my-app.servlet loads some stuff I need for the servlet, generates an HttpServlet class, and imports some classes so that I may load a jetty server and use gae's services (datastore, etc) in interactive mode (read, using SLIME with swank-clojure). Here's the namespace:


The magic that's left is, after issuing the defroutes and defservice command, the following (thanks to r0man for the tip!):


So here we are, running a webapp that can be deployed to gae (if you have read the linked posts, you'll see that you also need a web.xml and a appengine-web.xml to deploy, and you'll also need to comment out the ring.adapter.jetty from your namespace - gae already has its own application server :). Now by running the local server via (start-server) and not via gae's dev_appserver.sh shell script, you can happily work, on slime, redefine your servlet actions and refresh the browser to see your changes. Yay!
One problem, though. How do I use google's services? appengine-clj to the rescue, browse the code (see the test-suite for examples, specially on how you can test them locally using macros like appengine-clj.users/with-user-info). I was basically a happy camper until I got to try out user logins. GAE has this method, createLoginURL and createLogoutURL (applied to a UserService and a destination page string), that takes us to a dummy login screen. To be able to use this Service, I wrote the following code (loaded before starting the jetty server!):


But while this compiles perfectly, I noted that the login screen is not loaded, i.e., clicking the login link yields a 404 page. Not good. But it should be loadable, since the dev_server has it. Google's documentation isn't much help here, and I can't seem to find how on earth I access that screen (I need it to try out administration pages!). So feel free to drop a comment if you happen to know the solution for this!
To conclude, I'm not going to publish my application as a "blank example", as there are already some around. That said, if you have a question about this setup, just ask and I'll be as helpful as I can!

Friday, May 28, 2010

On Clojure error messages, II: ask and ye shall receive

I now realize my previous post carried some strong emotions, most of them not too good, and I want to humbly apologize for it. Let me state (again) that I'm enjoying working with clojure (for the most part, at least).

I wrote about the useless (wrong?) error messages, specifically when passing a list instead of a vector (ISeq) as arguments for a defn. After experimenting a bit, I was even more confused: (defn x () 1) complaints about the integer, so does (defn x () [] 1) and (defn x () [1]), clojure just doesn't know how to create an ISeq from that integer. I now understand this makes sense because you can specify multiple arity functions, like this:

(defn x

  ([] (x 0)

  ([x] (+ x 1)))

So in this case, if a vector isn't found where the arguments are expected, clojure complains, as he can't make an ISeq.

But none of this matters anymore (to the language user). Stuart Halloway (author of the book that I used to learn about Programming Clojure, which by the way I advise you to read, if you haven't already) was almost to fast picking up this issue! I have just received his tweet with a fix to this problem: clojure (the snapshot version) now detects if the arguments are a proper vector, and if not warns us with a much clearer message: "Parameter declaration arg1 should be a vector". This should satisfy all with the same issue I tackled on the previous post; more advanced users dealing with multiple arity defns should already be aware of the syntax, so it's safe for both cases.

This was a positive outcome in more than one way. Not only clojure got a bit better, but I got reminded of how I should had followed a much nicer "netiquette". I made a public complaint, and Stuart was impeccable to pick it up, hacking a fix and letting me know about it (everyone should learn from him, including myself!). But instead of posting my complaint (again, sorry if my tone was to harsh), I should had (1) ask on a discussion list or on other social platform about this; (2) take a look into the source code, see where the issue could be fixed, write a patch, and submit it to approval to the developers - alternatively, take the oportunity to learn how to do those things, and at least let the maintainers know about it, so a bug report is issued. This is the organization that most projects require to evolve properly.

Thursday, May 27, 2010

On Clojure error messages.

I know. I'm late to this train. And there are lots of resources to clarify this. But I have to manifest myself somewhere (and twitter's char limit won't do this time).

Here's the deal. I know I've written a fair share of Clojure lines of code. But I come from the land of the ancient parenthesis (specifically, Scheme, Common Lisp). So whenever I try to teach clojure to someone, it's inevitable to tell them that it's a Lisp, so it's ok to see those rounded delimiters everywhere.

This is where I start by asking them to define a simple function, and instead of defun/define, use defn. Something like this will do:

(defn xpto ()

  (+ 2 3))

Simple enough, right? Wrong. (I know it's wrong, now, off course). But for the beginner, the first thing to do is to read the error message. So let's take a look:

Don't know how to create ISeq from: clojure.lang.Symbol

  [Thrown class java.lang.IllegalArgumentException]

Yeeeah, isn't that obvious? Clojure wants to make a sequence and I'm trying to use a symb... wait, what?? the only symbol I know I'm using is xpto, and that's about right on the syntax! The Java exception isn't much help either. What argument? The ones I'm not using on the functions (but weren't those parameters?) Or the ones I'm using on the function call (but 2 and 3 are numbers, not strings!! *help*!) Ok, breath. let's take a look into the stack trace, it is usually helpful on java, at least to trace where the error is:

Backtrace:

  0: clojure.lang.RT.seqFrom(RT.java:469)

  1: clojure.lang.RT.seq(RT.java:450)

  2: clojure.lang.RT.first(RT.java:538)

  3: clojure.core$first.invoke(core.clj:53)

  4: clojure.core$sigs$asig__3331.invoke(core.clj:202)

  5: clojure.core$sigs.invoke(core.clj:214)

  6: clojure.core$defn.doInvoke(core.clj:268)

  7: clojure.lang.RestFn.invoke(RestFn.java:495)

  8: clojure.lang.Var.invoke(Var.java:381)

  9: clojure.lang.AFn.applyToHelper(AFn.java:180)

10: clojure.lang.Var.applyTo(Var.java:482)

11: clojure.lang.Compiler.macroexpand1(Compiler.java:5215)

12: clojure.lang.Compiler.macroexpand(Compiler.java:5270)

13: clojure.lang.Compiler.eval(Compiler.java:5338)

14: clojure.lang.Compiler.eval(Compiler.java:5320)

15: clojure.core$eval.invoke(core.clj:2366)

16: swank.commands.basic$eval_region.invoke(basic.clj:47)

17: swank.commands.basic$eval_region.invoke(basic.clj:37)

18: swank.commands.basic$eval801$interactive_eval__802.invoke(basic.clj:66)

19: clojure.lang.Var.invoke(Var.java:365)

20: myproject.core$eval3896.invoke(NO_SOURCE_FILE)

21: clojure.lang.Compiler.eval(Compiler.java:5353)

22: clojure.lang.Compiler.eval(Compiler.java:5320)

23: clojure.core$eval.invoke(core.clj:2366)

24: swank.core$eval_in_emacs_package.invoke(core.clj:94)

25: swank.core$eval_for_emacs.invoke(core.clj:241)

26: clojure.lang.Var.invoke(Var.java:373)

27: clojure.lang.AFn.applyToHelper(AFn.java:169)

28: clojure.lang.Var.applyTo(Var.java:482)

29: clojure.core$apply.invoke(core.clj:536)

30: swank.core$eval_from_control.invoke(core.clj:101)

31: swank.core$spawn_worker_thread$fn__453$fn__454.invoke(core.clj:300)

32: clojure.lang.AFn.applyToHelper(AFn.java:159)

33: clojure.lang.AFn.applyTo(AFn.java:151)

34: clojure.core$apply.invoke(core.clj:536)

35: swank.core$spawn_worker_thread$fn__453.doInvoke(core.clj:296)

36: clojure.lang.RestFn.invoke(RestFn.java:398)

37: clojure.lang.AFn.run(AFn.java:24)

38: java.lang.Thread.run(Thread.java:637)


Read it all? Want your 3 minutes back? (ok, 30 if you actually went looking for documentation on the API, the source of Compiler, core.clj or worse if you went looking for slime's or Thread :) ). Sick, isn't it? not a single line is useful for our cause.

I'm afraid I have no good news for you, except to tell you what the problem was and hope you'll never forget that. I know I didn't. (until I swapped to a bunch of different programming languages, including common lisp, for a while, and returned with my auto-pilot coding style turned on :) ).

The problem is that clojure expects a sequence of parameters, not a list. And thus, the proper syntax is to use [] instead of (). I know, a list is not a symbol. Or so I thought... I could even go theorize about () being translated to nil in compile time, and so it was a symbol. But evaluating (symbol? nil) quickly clarifies that for us...

Pledge - please, oh please start adding useful semantic to clojure's core language errors... The language entry barrier will lower significantly, I'm sure!

Monday, June 01, 2009

ELS 2009 - my impressions

I've finally got to attend an international Lisp meeting — one more item crossed off the checklist!

The European Lisp Symposium 2009 was held in Milan, Italy, during the 27-29 of May. The program featured some interesting presentations, and while I'm not going to go a complete overview of them all, in this post I'll go over the bits that got into my head the most. This means, don't be offended or ignored if your work (or the work you were expecting to read about) isn't mentioned here. It probably means my mindset isn't properly configured, yet :)

The first day of the conference was just the reception, where I got to meet great people. Among the entire conference I got to meet people I've already read about in the web-o-sphere such as Stellian Ioanescu, Scott McKay, Mark Tarver, Nikodemus Siivola, Pascal Constanza and Christopher Rhodes. I also got to know some nice people I didn't know, including Didier Verna, Jim Newton, Claus Brod and Edward Dogde. António Leitão, my PhD supervisor and program commitee chair, introduced me to Mark Feeley, from Termite and Gambit Scheme, who told me about a Gambit package, JSS (a multithreaded javascript compiler), which I must try when I get back home. Most of all, despite some ideological divergences between some of the participants, the mood was quite pleasant, and joyful. After all, Lisp is supposed to bring happiness to those who use it.

The second day started with a Scott McKay talk on his life's experiences, and mistakes. He has grown a pretty strong aversion to incremental code fixes to correct fundamental problems. Pretty much all he's done made him believe that full rewrites gives us the opportunity to think better about the design, and that we cannot try to simplify the code by extending it. He is also concerned about the current "big thing": concurrency. May languages are addressing it, and Common Lisp is getting behind each day that passes. Clojure tackled it, but it carries the known set of burdens. Scott recognizes the great one-man effort, but wonders if it's easier to improve Clojure or to design a new Lisp and get it right from design. This could rapidly solve, for instance, the namespaces Common Lisp problem (instead of having symbols, packages, labels, macros, symbol-macros, etc, etc (Pascal counted 9 different namespaces), we could have one single namespace). The same goes to the type system, *everything* should inherit from the same root object type.

Mark Tarver gets an almost similar position, but he "strayed away" from Common Lisp, and went looking for answers on both Scheme and Python. Because he couldn't find them, he designed Qi, a language that is supposed to offer what he believes to be the best language features.

I found the presentation on hygienic macros for the unhygienic world quite motivating. By using a few helper macros, Pascal Constanza demoed how we can emulate the former on Common Lisp, which is quite useful, specially if you come from the Scheme world. All at the expense of a few extra language constructs, but not too distracting ones.

Charlotte Herzeel presented an interesting approach to implement Software Transactional Memory (STM): she implemented a (limited, not feature-complete) Scheme interpreted within Common Lisp. Doing this allowed her to have access each memory access point easily (she only has to address cell and vectors accesses. The thing is, by having her interpreter, she easily tapped to the code segments where data access is done, via reflection. So it becomes easy to experiment with STM algorithms.

I found out the industry is not sticking to widespread CL implementations. At least three different companies (mostly related to the CAD/graphics world, but I think it's a coincidence) rely on SKILL, or some adaptation of it. SKILL is a small footprint Lisp-like scripting language, and that makes it appealing for many industrial domains. However, it appears to be quite obsolete, undocumented and unsupported. It was nice, though, to see some successful uses of Lisp.

I was kinda disappointed not to see Kent Pitman, I believe he canceled at the last minute. I was also looking forward to see some Clozure CL people there, I'd like to hear about what they have in mind about Cocoa and iPhone development. They already have a great Objective C bridge, but as a Common Lisp, things are entitled to be much easier, specially in order to produce competitive small products (there's a big niche for small simple applications on MacOS, due to Apple's design principles)

Marco Antoniotti was a great host on Milan. He organized a great banquet at Osteria del Treno, where we all got to share some more insightful comments about the entire conference and more. The day after that, Marco wore the cicerone cap and took everyone that was still in Milan for a great Futurismo Exhibit, where we got to learn some amazing bits of the Italian cultural inheritance (definitely not my area of expertise, but it was quite interesting to try to interpret some works and sell my ideas to the guide, despite failing most of the times :) ). That afternoon we visited the Duomo, a massive cathedral on the center of Milan. The most impressive thing for me was to realize the wow-factor was even greater from inside of it (on it's roofs), than from the outside!

All in all, it was a memorable experience, everything went great (i wasn't even bugged with the wireless access difficulties that so many people were forced to have, since i had the eduroam credentials already set up on my machine!). Next year it'll be in Lisbon, so I'll be attending to. Meanwhile, I'll look forward to go to Italy again on July for the 6th European Lisp Workshop (within ECOOP).

Wednesday, January 28, 2009

Lisp macros, eval and packages

Today I spent about an hour trying to find out the source of a bug in the code for my PhD prototype. To make the context short, I need to have a class definition to be stored, and loaded afterwards. And I was using Gary King's time-saver metatilities:defclass* to reduce the required coding. The problem was when I wanted to load such a definition in a generic method, I was evaluating the definition expression - one of the acceptable uses of `eval', correct me if I'm wrong, is to interpret something that was just read (in this case, from a serialized string, from other servers). The code in question was something like this:

(defmacro load-data (name attributes)
  "Defines a domain concept, using metatilities:defclass* syntax."
  `(progn
     (metatilities:defclass* ,name (data-item)
       (,@attributes)
       (:metaclass profiled-metaclass)
       (:name-prefix  ,(format nil "~(~A~)" name)))
     (info "Data type loaded: ~A" ',name)))

(defmethod load-definition ((def data-item-definition))
  (eval (macroexpand `(load-data ,(definition-name def)
                                                     ,(data-item-definition-attributes def)))))

What I was getting as a result is that the auxiliary methods created as accessors by defclass* weren't being imported in my packaged, but in CL-USER. Hence, lots and lots of compiler warnings and subsequent errors when trying to use those accessors. I fiddled around, tried to see if I could remove the eval, but the solution, so obvious as I know can see, is quite simple. Just place your evaluated expression after setting the package. The fixed method is the following:

(defmethod load-definition ((def data-item-definition))
  (eval `(progn (in-package :dshow)
                ,(macroexpand `(load-data ,(definition-name def)
                                          ,(data-item-definition-attributes def))))))

Hope you can see this before spending too much time on a similar bug!

Saturday, October 25, 2008

Milky love for lispers

I've just updated my "Remember The Milk"-talking lisp library. Now you can access their API with a simple CLOS-based object model.

You can fetch the latest version by direct download, SVN and/or by asdf-install from the project page, where I have the important updates:

Recent Changes

* Added an object bridge to make the API even more integrated with the language.

* Methods and functions were coded to be easier to manage a local state of the RTM user data.

Future Work

* Improve synchronization and bandwidth usage by fetching only recently updated data;

* Provide offline work for the local data

Monday, April 14, 2008

Moooing away in Common Lisp

I'v recently found myself needing to use a task manager to make some bulk operations (to be more precise, I wanted to copy all of my tasks to a device with no built-in synchronization mechanism for those). I happen to make use of the great Remember The Milk Web application (I've previously worked with Emacs Planner, but I had to drop it in favor of a more mobile version of my life).

Enter Common Lisp. Perhaps the fastest way to do some scripting in my mind, but I've yet to make a library to use a Web-based API. Turned out it was quite clean, and in about 5 hours of work I had the whole API grokked, coded, tested and hosted in GoogleCode here. (I looked into cl.net, but found the google's approach to hosting much more featured for the fast start I was looking for. If this has enough momentum I can look into it again, with more time - the main advantage would be asdf-installability, I suppose.)

I already had experience making project "skeletons" (asdf project file, package declaration, etc.). So the hardest thing I had to do was look into the web API call mechanism and into the md5 encryption. If you don't need the detailed description, tha answers are, respectively, Drakma and Ironclad. ( I also use cl-json to parse RTM's responses into a lisp-friendly format.)

To call a Web-based method, we need to make an HTTP request, and be able to read the response. using drakma (asdf installable and loaded in the usual way), all I had to do was something like:

(http-request rtm-api-endpoint :method :post :parameters '(("param-name" . "param-value")))

With some parameter abstractions, RTM's was easily tamed. A call to one of their methods is now made with the following macro:

(defun rtm-api-call-method (method &optional key-value-pairs &key with-timeline with-authentication (format "json"))
  "Calls `METHOD'.
 - Optionally passes pairs of strings in `KEY-VALUE-PAIRS' in the form
of (`PARAMETER' . `VALUE').
 - Keyword `WITH-TIMELINE', if not null, allows the method to be called within
the `*CURRENT-TIMELINE*'.
 - Keyword `WITH-AUTHENTICATION', if not null, allows the method call to be
authenticated with a valid `*RTM-API-TOKEN*'.
 - Keyword `FORMAT' is one of
\"json\" (the default value) or \"rest\", and
specifies the server reply format."

  (declare (special *current-timeline*))
  (let* ((parameters `(("api_key"    . ,rtm-api-key)
                       ("method"     . ,method)
                       ("format"     . ,format)
                       ,@(when with-timeline
                               (with-timeline
                                 `(("timeline" . ,*current-timeline*))
)
)

                       ,@(when with-authentication
                            `(("auth_token" . ,*rtm-api-token*))
)

                       ,@key-value-pairs
)
)

         (api-sig (compute-rtm-api-sig parameters))
)

    (multiple-value-bind (result)
        (http-request rtm-api-endpoint
                      :method :post
                      :parameters `(
                                    ,@parameters
                                    ("api_sig" . ,api-sig)
)
)


      (let* ((response (json-bind (rsp) result rsp))
             (stat (assoc :stat response))
)

        (cond
          ((string=  (cdr stat) "ok")
           (rest response)
)

          ((string=  (cdr stat) "fail")
           (let ((err-info (cdr (assoc :err response))))
             (error "RTM error code ~a: ~a~%" (cdr (assoc :code err-info))
                    (cdr (assoc :msg err-info))
)
)
)
)
)
)
)
)

With this (rather big, for the sake of readability, or mayhap due to my lack of experience in mental pretty printing) function, I define a call to an RTM module simply by coding:

(defun rtm-api-tasks-complete (list-id taskseries-id task-id)
  (rtm-api-call-method "rtm.tasks.complete"
                       `(("list_id"       . ,list-id)
                         ("taskseries_id" . ,taskseries-id)
                         ("task_id"       . ,task-id)
)

                       :with-authentication t
                       :with-timeline t
)
)

The only call in the first function definition that cannot be easily guessed how they work is the compute-rpm-api-sig-parameters. This is the function that performs the algorithm required by RTM to encode all parameters and guarantee authenticity in each request (along with a masked API key). Basically it does some mambo-jumbo concatenation with each parameter's name and value, and then performs an MD5 to get the equivalent hash code. Easy, right? But I'm a lazy programmer. That, and I truly believe there's no point in reinventing the wheel, so I looked for encryption functions in Lisp, and I found Ironclad, a collection of most of these functions in Lisp. So producing an md5 functions was as easy as the following:

(defun md5 (string)
  "MD5 uses ironclad to encode `STRING' into an hexadecimal digest string."
  (ironclad:byte-array-to-hex-string
   (ironclad:digest-sequence :md5 (ironclad:ascii-string-to-byte-array string))
)
)

And that's about it. The rest was toying around, the API works perfectly (kudos to the RTM dev team!), and I was thrilled to have my tasks exported in a jiffy. If you want to find more info, feel free to snoop through the code (it's quite easy to grasp, I think, and relatively small), in the Google Code site: http://code.google.com/p/rtm-lisp-api/ . So now, what would you, gentle reader, do with this API? Drop me some comments with your ideas.

Until the next time!

Thursday, March 13, 2008

Cocoa development, using a Lisp bridge

Let's get a bit away from my PhD for a while. In my spare time, I've been looking at some graphic libraries to make some applications. In the past I've looked for Operating System portability for those apps. I've also delved into the Web world for interfaces. Right now, I've settled for making pretty looking gui's. If you add my new acquisition - a Macbook Pro, my first mac ever! - and I obviously had to try to make a MacOS Cocoa application. They're fashion, they're usable, they mingle with the rest of the desktop manager, and I was just tempted to try to use Lisp to make something like it.

Fortunately, this wasn't so hard, has OpenMCL has a great step by step tutorial (to be taken with a few glasses of water and with the Cocoa / Interface Builder tutorials made available by Apple). This tutorial has detailed instructions of how one can build the Interface with the WYSIWYG tool that comes with Xcode. Then it tells you how to setup the connection points between the interface and the application code. These are called outlets, for the variables in the code that represent a given object (so that you may, for instance, retrieve the text in a text field) and actions, for the functions that are called when something happens in the interface (e.g., user click in a button). After creating the necessary objects (basically you must make them belong to a specific metaclass in order for them to be exported as an ObjectiveC class), all you have to do is call a function that binds together the compiled code, the Interface files (in the nib format) and places a nice application bundle in the directory of your choice. It can't get any easier, you think. And yes, you may code interface changes in you lisp code. But it's extremely easier to follow in Interface Builder guidelines and helpers... You just can't go wrong!

You may find the tutorial at the OpenMCL wiki: http://trac.clozure.com/openmcl/wiki/AppleCurrencyConverter