Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing Common Lisp code that executes from the command line, but not inside the interpreter

When writing Common Lisp code, I use SLIME. In particular, I compile the buffer containing definitions of functions by using C-C C-k, and then switch to the REPL to run those functions. Putting executable code to run those functions in the buffer does not appear to work so well. If the code has bugs it can make a mess.

It would be handy to have a way to include code that doesn't get compiled in the buffer, but do get run from the command line, e.g. when doing

sbcl --script foo.lisp

If that were the case, I would not have to keep adding and removing code every time I wanted to run code from the command line. Does there exist such a condition?

This is analogous to the Python condition.

if __name__=='__main__':

which is false if a Python file is imported as a module, but true if it is run as a script.

This blog post entitled "Using SBCL for Common Lisp shell scripting", found by random Googling, has

;; If run from command line, the following if-test will succeed

(if (> (length sb-ext:*posix-argv*) 1)

    ;; Code that is executed from the command line only goes here

)

The code included indeed does not get run by the compiler inside SLIME, but it doesn't get run by sbcl --script either.

UPDATE: Thanks to Vsevolod Dyomkin for his helpful answer and the followups. Some notes about that answer follow, compiled from the comments to that answer. @Vsevolod, if you add these to your answer, I'll delete them.

  1. First, I asked for a way to run code from the command line, but not from the interpreter. The supplied solution does more; it also gives a way to run code from the interpreter but not the command line.

  2. The first step is to define a reader macro function for the macro character #!. As stated in the link "Upon encountering a macro character, the Lisp reader calls its reader macro function". The reader function is defined by the call to set-dispatch-macro-character. So, when the #! character is seen, the set-dispatch-macro-character causes the lambda function defined in the body to be called. This function then adds the keyword :noscript to the *features* variable. See also a discussion of what reader macros are good for in the SO question Read macros: what do you use them for?.

  3. Observe that the keyword :noscript is added to *features* precisely when the #! character is present. Furthermore, the #! character is present when the code is run inside the interpreter e.g. when using slime, but apparently is absent (removed) from program's
    text by sbcl --script is run. Therefore, :noscript is added to *features* when the code is run in the interpeter, but not when run as a
    script.

  4. We now use the builtin reader macros #-/#+, which as Vsevolod said, behave similarly to the to C's #IFDEF/#IFNDEF. They check for a symbol
    in *features*. In this case, #-:noscript checks for the absence of :noscript, and #+:noscript checks for the presence of :noscript.
    If those conditions are satisfied, it runs the corresponding code. To wrap a block of code, one can use progn like this: #-:noscript (progn <your code here>).

  5. Finally, one needs to call set-dispatch-macro-character before running code that uses this functionality. In the case of sbcl, one can put it in the initialization file ~/.sbclrc. Observe that this approach does not depend on the Common Lisp implementation being SBCL.

  6. A simpler alternative, as mentioned in the sbcl-devel list, is to use the fact that the keyword :SWANK appears when one types *features* in
    a REPL inside emacs using SLIME. SWANK is the server side of SLIME. SLIME should probably more accurately called SLIME/SWANK, as these two are the client/server components of a client-server architecture. I found this blog post called Understanding SLIME, which was helpful.

    So, one can use #-:swank and #+:swank just like #-:noscript and #+:noscript, except that one doesn't need to write any code. Of course, this then won't work if one is using the command line interpreter sbcl, for instance, since then :SWANK will not appear in *features*.

like image 728
Faheem Mitha Avatar asked Mar 20 '12 23:03

Faheem Mitha


People also ask

How a Lisp program can be executed?

Step 1: After logging into a CUIT machine, enter "lisp" after the $ shell prompt and then hit <return>. Another way is to run lisp via emacs: Meta-x run-lisp (i.e. hit 'esc' followed by 'x', type "run-lisp" and you'll be in lisp mode from which you can load files of lisp code...)

How do you exit a Lisp interpreter?

To terminate the Lisp system, use the command ":exit" or call the function "(exit)."

What is Lisp interpreter?

Little Lisp is an interpreter that supports function invocation, lambdas, lets, ifs, numbers, strings, a few library functions, and lists. I wrote it for a lightning talk at the Recurse Center to show how easy it is to write an interpreter. The code is 116 lines of JavaScript.

How do I run a Lisp code in Emacs?

In a fresh Emacs window, type ESC-x lisp-interaction-mode . That will turn your buffer into a LISP terminal; pressing Ctrl+j will feed the s-expression that your cursor (called "point" in Emacs manuals' jargon) stands right behind to LISP, and will print the result.


1 Answers

Fare Rideau wrote a nifty unix utility CL-Launch, which enables executing lisp software from the command line. It has integrated Quicklisp support and works on most of the Common Lisp implementations.

Example script may look like this:

#!/usr/bin/cl -sp "hunchentoot" -Q -E main

(defun main (argv)
  (format t "~A: ~{~A ~}~%" (truename ".") argv)
  (hunchentoot:start
   (make-instance 'hunchentoot:acceptor
                  :document-root (truename ".")
                  :port 8080))
  (do ((x #\s (read-char)))
      ((char-equal x #\q) nil)))

After adding +x permissions to script and invoking it, it will start http server in the current directory. "-sp" flag indicates package you want to load, so it's fairly clean way of abstracting shell script from the package.

For more details refer: http://cliki.net/CL-Launch

like image 180
Daniel Kochmański Avatar answered Oct 08 '22 18:10

Daniel Kochmański