Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp equivalent to Haskell's main function?

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))
like image 522
mcandre Avatar asked Nov 26 '10 13:11

mcandre


1 Answers

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)))
like image 129
mcandre Avatar answered Sep 29 '22 19:09

mcandre