Common Lisp as a Scripting Language, 2015 Edition
fare.livejournal.com
fare.livejournal.com
Here is a reimplementation of "cat" in it:
#!/usr/bin/env imp
(def copy-out (proc (x)
(let f (if (file? x) x (open x))
bytes (read default-chunk f)
(if bytes
(seq (write bytes stdout)
(recur f))
(close f)))))
(if (nil? script-args)
(copy-out stdin)
(each copy-out script-args))
Running external programs is a bit more verbose than normal shell, but there is some optional reader-macro sugar on top of fork+exec, e.g. the effect of the following is that /usr/bin/say gets run with those non-string args converted to strings and a voice comes out of my speaker. !(say hello there)
=> ((status : 0) (pid : 2945) (in : [File]) (out : [File]) (err : [File]))fair enough!
> get at the essence of what shebang-style unix scripting was about
FWIW, although convoluted, you can do that with guile, with:
#!/usr/bin/guile \
-e main -s
Or simpler with chicken: #!/usr/bin/csi -sSome good examples of scsh scripting (some by the author, Olin Shivers) can be found at
http://scsh.net/resources/scripts.html
The manual is also very good:
The acknowledgements section made my morning, thanks.
Last time I checked a package for scsh for Fedora was somehow broken and/or conflicting with Chicken and I went with the latter. In general I like the idea and APIs of scsh, I'm just afraid that there will be no one to ask for help if I hit some problems. With Chicken or Racket the communities are active and it's easy to find support. How does this look in case of scsh?
You will always learn something by releasing it.
#!/usr/bin/sbcl --script
in your .lisp file.
BTW, Clojure is "out" for command line tools because of the JVM startup time but I have thought about Clojurescript + node.
(import [sh [cat grep wc]])
(->
(cat "/usr/share/dict/words")
(grep "-E" "^hy")
(wc "-l"))I think it's 64-bit (?). Most of the time it hasn't mattered for me, at least when writing scripts.
You can also just build the "old" version (0.6.7) with the `-m32` GCC flag, and it works fine on 64-bit Linux and OS X. It's very stable in my experience, and works fine.
cat <<eof > Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world!"); }}
eof
javac Hello.java
echo "Main-Class: Hello" > manifest.mf
jar cvfm hello.jar manifest.mf Hello.class
time java -jar hello.jar
Hello, world!
real 0m0.153s
user 0m0.132s
sys 0m0.020s
vs: lein new hello
cd hello
# Pesty s-expressions, so hard to work with... ;-)
cat <<eof|patch -p0
--- project.clj 2015-04-16 04:13:09.734160136 +0200
+++ project.clj.patch 2015-04-16 04:09:33.809504079 +0200
@@ -3,4 +3,5 @@
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
+ :main hello.core
:dependencies [[org.clojure/clojure "1.6.0"]])
eof
cat<<eof > src/hello/core.clj
(ns hello.core
(:gen-class))
(defn -main
"I don't do a whole lot."
[]
(println "Hello, World!"))
eof
lein uberjar
time java -jar target/hello-0.1.0-SNAPSHOT-standalone.jar
Hello, World! real 0m1.060s
user 0m1.400s
sys 0m0.040s
(Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz, SSD drive) wget ftp://ftp.gnu.org/pub/gnu/kawa/kawa-2.0.jar
wget ftp://ftp.gnu.org/pub/gnu/kawa/kawa-2.0.jar.sig
gpg --recv-key D269E756
gpg --verify kawa-2.0.jar.sig
echo '(format #t "Hello, world!\n")' > hello.scm
# Not sure how to bundle up a scheme script with kawa
# to a stand-alone jar...
java -jar kawa-2.0.jar --main -C hello.scm
time java -cp kawa-2.0.jar:. hello
Hello, world!
real 0m0.284s
user 0m0.296s
sys 0m0.020s # First run:
time guile hello.scm
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
(...)
Hello, world!
real 0m0.066s
user 0m0.044s
sys 0m0.020s
#Ed: with precompiled code under $HOME/.cache/guile (?)
time guile hello.scm
Hello, world!
real 0m0.040s
user 0m0.036s
sys 0m0.004s pi@raspberrypi ~/lisp/ccl $ time ./armcl -n -Q -e '(progn (princ "hello") (quit))'
hello
real 0m0.112s
user 0m0.020s
sys 0m0.080s
And the expression is first compiled to native code...I do have some compiled programs I use, but IMO they're a little too big to be called scripts.
An interesting idea would be the ability to dump a shared library of the core image, and then dump incremental changes as executable images that dynamically link to it.
If you can cut the size of the core language's image in half with just a simple method like this, you could probably get impressive results using more sophisticated methods on images requiring a lot of libraries: https://gist.github.com/burtonsamograd/f08f561264ff94391300
If one doesn't want to compile first, that's fine. The interpreter's startup time is negligible.
I know what he means. These designers never learn...