Page 1 of 1

Using libraries in CLISP scripts

PostPosted: Sun Jun 30, 2013 10:50 am
by aidlt
Hi all.

I'm trying to create a simple CLISP script and I'd like to find out what are the most efficient and common ways of loading a library.

The script should take a line from stdin and display a message box containing this line. I'm using LTK.

This is the Python prototype:
Code: Select all
#!/usr/bin/env python3

# show-message.py

from tkinter import *
from tkinter import messagebox

def show_message(txt):
    root = Tk()
    root.withdraw()
    messagebox.showinfo("", txt)
    root.destroy()

def main():
    show_message(input())

main()

It runs pretty well:
Code: Select all
$ time echo hello world | ./show-message.py

real   0m1.381s
user   0m0.132s
sys   0m0.020s

The `real' time doesn't matter as it depends on when the user press the OK button.

Basicly I'm not sure about what the Lisp counterpart of the import statements should be.

I use quicklisp, so the straightforward solution was as follows:
Code: Select all
#!/usr/bin/env clisp

(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))
(ql:quickload :ltk)

(in-package :ltk)

(defun show-message (txt)
  (with-ltk ()
    (format-wish "wm withdraw .")
    (do-msg txt)
    (exit-wish)))

(defun main ()
  (let ((msg (read-line nil nil nil)))
    (when msg
      (show-message msg))))

(main)

The `load' doesn't look especially elegant, but let it be. Much worse is that there's a noticeable delay. Indeed,
Code: Select all
$ time echo hello world | ./show-message.lisp >> /dev/null

real    0m1.449s
user    0m0.508s
sys 0m0.080s

So user time is nearly four times greater compared to Python.

I also tried to use asdf directly. I copied asdf.lisp into the same directory as the script, compiled it, created the directory `asdf' in my home directory, and created a symlink to ltk.asd (sitting deep in the quicklisp dir) in `asdf'. My preamble became as follows:
Code: Select all
(load 'asdf)
(push (merge-pathnames "asdf/" (user-homedir-pathname)) asdf:*central-registry*)
(asdf:load-system 'ltk)

The performance improved (not drastically, but all the same):
Code: Select all
$ time echo hello world | ./show-message.lisp >> /dev/null
WARNING: Replacing method
          #<CLOS:STANDARD-WRITER-METHOD
            (#<BUILT-IN-CLASS T> #<STANDARD-CLASS TREEITEM>)>
         in #<STANDARD-GENERIC-FUNCTION (SETF TEXT)>
WARNING: Replacing method
          #<CLOS:STANDARD-WRITER-METHOD
            (#<BUILT-IN-CLASS T> #<STANDARD-CLASS TREEITEM>)>
         in #<STANDARD-GENERIC-FUNCTION (SETF IMAGE)>
0 errors, 2 warnings

real   0m1.277s
user   0m0.308s
sys   0m0.044s

Probably I could do with this script being two times slower than in Python (luckily I don't know Perl :D). However, I'm afraid my solution is rather awkward.

Re: Using libraries in CLISP scripts

PostPosted: Sun Jun 30, 2013 2:09 pm
by aidlt
So far SBCL wins, both in performance and in outlook. It's a pity it doesn't support shebang.
Code: Select all
(require 'asdf)
(push (merge-pathnames "asdf/" (user-homedir-pathname)) asdf:*central-registry*)
(require 'ltk)

$ time echo hello world | sbcl --script show-message-sbcl.lisp

real   0m1.202s
user   0m0.268s
sys   0m0.044s

Re: Using libraries in CLISP scripts

PostPosted: Mon Jul 01, 2013 1:25 am
by Goheeca
SBCL supports the shebang via the switch --script.
Code: Select all
#!/usr/bin/sbcl --script

(defun argv ()
  (or
   #+clisp (ext:argv)
   #+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*
   nil))

(format t "~&~{~a~^ ~}~%" (argv))

Re: Using libraries in CLISP scripts

PostPosted: Mon Jul 01, 2013 2:18 am
by aidlt
Thanks, Goheeca, that's great! Both the news and the function, I mean. :)

BTW apparently the most speedy approach is to put ltk.fas(l) in the script's directory and load it, then SBCL runs as fast as Python and CLISP is just a little bit slower. However, this is very ad hoc. Perhaps the right thing is to save an image containing quicklisp. The scripts become cleaner and the performance is decent.