4. Programming questions

4.1. How do I write a "Hello, World!" programme in Lisp?
4.2. How do I make an executable from my programme?
4.3. How do I run my programme as a script, then?
4.4. What is the Lisp equivalent of the __FILE__ and __LINE__ ANSI C preprocessor macros? How do I find out where an error occurred?
4.5. How do I split a string?
4.6. Why doesn't Common Lisp have continuations?
4.7. How does (defun car (x) (car x)) work?
4.8. Does anyone actually use FLET?
4.1.

How do I write a "Hello, World!" programme in Lisp?

This is actually a subtle question; not in the respect of computing "Hello, World!", obviously, but because of what being a "Hello, World!" programme actually means.

At its simplest, you can simply type "Hello, World!" at the REPL, to find that the `P' part of that will print "Hello, World!" back to you. However, this won't do what you want if this is in a file, as return values aren't printed unless they are at the REPL.

Something which is closer to the canonical "Hello, World!" attempt is (write-line "Hello, World!")

4.2.

How do I make an executable from my programme?

This depends on your implementation; you will need to consult your vendor's documentation.

  • With ECL and GCL, the standard compilation process will produce a native executable.
  • With LispWorks™, see the Delivery User's Guide section of the documentation.
  • With Allegro Common Lisp™, see the Delivery section of the manual.

However, the classical way of interacting with Common Lisp programs does not involve standalone executables. Let's consider this during two phases of the development process: programming and delivery.

Programming phase: Common Lisp development has more of an incremental feel than is common in batch-oriented languages, where an edit-compile-link cycle is common. A CL developer will run simple tests and transient interactions with the environment at the REPL (or Read-Eval-Print-Loop, also known as the listener). Source code is saved in files, and the build/load dependencies between source files are recorded in a system-description facility such as ASDF (which plays a similar role to make in edit-compile-link systems). The system-description facility provides commands for building a system (and only recompiling files whose dependencies have changed since the last build), and for loading a system into memory.

Most Common Lisp implementations also provide a "save-world" mechanism that makes it possible to save a snapshot of the current lisp image, in a form which can later be restarted. A Common Lisp environment generally consists of a relatively small executable runtime, and a larger image file that contains the state of the lisp world. A common use of this facility is to dump a customized image containing all the build tools and libraries that are used on a given project, in order to reduce startup time. For instance, this facility is available under the name EXT:SAVE-LISP in CMUCL, SB-EXT:SAVE-LISP-AND-DIE in SBCL, EXT:SAVEINITMEM in CLISP, and CCL:SAVE-APPLICATION in OpenMCL. The

Application delivery: rather than generating a single executable file for an application, Lisp developers generally save an image containing their application, and deliver it to clients together with the runtime and possibly a shell-script wrapper that invokes the runtime with the application image. On Windows platforms this can be hidden from the user by using a click-o-matic InstallShield™ type tool.

4.3.

How do I run my programme as a script, then?

4.4.

What is the Lisp equivalent of the __FILE__ and __LINE__ ANSI C preprocessor macros? How do I find out where an error occurred?

There is no direct equivalent of __FILE__ and __LINE__ in ANSI Common Lisp; this is perhaps most simply explained by the fact that CL is not particularly a file-oriented and definitely not a line-oriented language. That said, your particular implementation may carry around some information about where functions were compiled, and COMPILE-FILE binds the special variables *COMPILE-FILE-TRUENAME* and *COMPILE-FILE-PATHNAME*.

      (defun foo () (break "Stopped inside ~S" (the-function-i-am-in)))
      
      (setf (symbol-function 'bar) (symbol-function 'foo))
      
      (bar)
    

Are you in a breakpoint in FOO or in BAR?

4.5.

How do I split a string?

There is no `right' answer to this question; many lisp programmers have rolled their own solution in the past, and others are of the view that it should never be necessary, as long as all sequence functions are used with consistent :start and :end arguments.

However, a community-based `standard' was developed in June/July 2001 on comp.lang.lisp; known as SPLIT-SEQUENCE (formerly PARTITION), it works as follows in its simplest form:

(split-sequence #\Space "A stitch in time saves nine.") gives ("A" "stitch" "in" "time" "saves" "nine."), 28

For more details, consult the specification, available from its CLiki page.

4.6.

Why doesn't Common Lisp have continuations?

Continuations are a great theoretical tool; if a language has first-class, multiply invocable continuations then one can build threads, exceptions, coroutines, and the kitchen sink on top.

However, there is an implementation burden with continuations; supporting first-class, multiply invocable continuations complicates things tremendously for the Lisp implementor. The ANSI standardizing committee J13, mindful of this, took the view that it would be better to specify the user-level control structure (CATCH, UNWIND-PROTECT, and so on) and let implementors choose whether to build those on top of continuations or not.

If you need to play with continuations, you should use a Scheme implementation.

4.7.

How does (defun car (x) (car x)) work?

This code is probably part of the source to a lisp compiler, which knows how to open-code calls to CAR. However, the interpreter also needs to know how to call CAR, which is what the above defun is doing. This is not recommended in user code...

4.8.

Does anyone actually use FLET?

This question is usually motivated by the existence of LABELS, which is a similar form for binding functions, but also allows mutual recursion between the functions being bound. Given this, it is perhaps natural to question the utility of FLET.

However, there are two reasons for using flet: one idiomatic and one programmatic. The idiomatic reason is that flet can be useful to signal to the reader of the code that it is not expected that the functions will be mutually recursive; in other words, it is part of the documentation of the system, so that a subsequent programmer can see by inspection the purpose of binding the functions.

More usefully, though, flet can be useful to locally modify the behaviour of functions, for instance (a contrived example due to Kent Pitman):

      (defun square (x) (* x x))
      
      (flet ((square (x) (make-instance 'square :area (squarex)))) ...)