8

Haskell's main function does just what I want: evaluate when the file is loaded by itself (e.g. ./myfile.hs or runhaskell myfile.hs) and in no other case. main will not be called when the file is imported by another file. newLISP also has this functionality.

Is there equivalent code for Common Lisp?

I read the source code for CLISP. Here's what happens when the user enters clisp myfile.lisp or ./myfile.lisp:

  1. CLISP saves myfile.lisp as p->argv_execute_file.
  2. CLISP creates the expression (LOAD "p->argv_execute_file") and pushes it onto the Lisp stack.
  3. CLISP saves any additional command-line arguments in a list.
  4. CLISP stores the arguments in the Lisp variable *args*.

CLISP never makes a Lisp variable referring to p->argv_execute_file, so there is no way to discern whether myfile.lisp was loaded directly, by the user in the REPL, or by another Lisp file. If only (car *args*) were myfile.lisp, my task would be easy.

Note: Shebangs give CLISP trouble if the file is loaded from the REPL, so I put this code in ~/.clisprc.lisp:

(set-dispatch-macro-character #\# #\!
 (lambda (stream character n)
  (declare (ignore character n))
  (read-line stream nil nil t)
  nil))
mcandre
  • 22,868
  • 20
  • 88
  • 147

2 Answers2

2

I found a solution. It's a bit of shell trickery, but it works. I'll soon modify this to work on CL implementations other than CLISP.

#!/bin/sh
#|
exec clisp -q -q $0 $0 ${1+"$@"}
exit
|#

;;; Usage: ./scriptedmain.lisp

(defun main (args)
 (format t "Hello World!~%")
 (quit))

;;; With help from Francois-Rene Rideau
;;; http://tinyurl.com/cli-args
(let ((args
       #+clisp ext:*args*
       #+sbcl sb-ext:*posix-argv*
       #+clozure (ccl::command-line-arguments)
       #+gcl si:*command-args*
       #+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
       #+cmu extensions:*command-line-strings*
       #+allegro (sys:command-line-arguments)
       #+lispworks sys:*line-arguments-list*
     ))

  (if (member (pathname-name *load-truename*)
              args
              :test #'(lambda (x y) (search x y :test #'equalp)))
    (main args)))
Cody Reichert
  • 1,620
  • 15
  • 13
mcandre
  • 22,868
  • 20
  • 88
  • 147
  • The `exit` in line 4 is not necessary — due to `exec`, shell will never run it. And CL ignores it anyway. So line 4 can be removed – ulidtko Apr 28 '23 at 16:18
0

(eval-when (situation*) ...)

Update sorry for the confusing answer.

I could be wrong, but it seems to be impossible to do what you want exactly. I would make a shell script and call clisp -i myfile.lisp -x (main).

Is there any reason to not make it executable (described here)?

P.S. Common Lisp is a language and clisp is one of the implementations.

Community
  • 1
  • 1
khachik
  • 28,112
  • 9
  • 59
  • 94
  • :load-toplevel only works while the code is compiling and :execute calls main whenever the file is loaded, not quite the desired functionality. – mcandre Nov 26 '10 at 14:12
  • @mcandre `:load-toplevel` works when the file is loaded, but everything else is correct, I'm going to update the answer, thanks. – khachik Nov 26 '10 at 14:28
  • clisp -i myscript.cl wouldn't work well as a shebang. Also, clisp doesn't allow -x arguments when loading a script. But thanks anyway :) – mcandre Dec 01 '10 at 07:33