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))
1
  • Why do you need an equivalent to the main function? Commented Nov 26, 2010 at 21:45

2 Answers 2

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)))
Sign up to request clarification or add additional context in comments.

1 Comment

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
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.

3 Comments

:load-toplevel only works while the code is compiling and :execute calls main whenever the file is loaded, not quite the desired functionality.
@mcandre :load-toplevel works when the file is loaded, but everything else is correct, I'm going to update the answer, thanks.
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 :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.