Archive for October, 2007|Monthly archive page

My .screenrc

As per request, here’s my .screenrc:

# skip the startup message
startup_message off

# UTF-8 everywhere
defutf8 on

# Automatically detach on hangup.
autodetach on

# If a screen dies, don't freeze the whole screen waiting for it.
nonblock on

# Change default scrollback value for new windows
defscrollback 10000
scrollback 10000

# start with visual bell as default
vbell off
vbell_msg "Bell on %t (%n)"

# look and feel
caption always "%3n %t%? @%u%?%? [%h]%?%=%c"
termcapinfo xterm 'hs:ts=\E]2;:fs=07:ds=\E]2;screen07'
hardstatus alwaysignore
hardstatus alwayslastline '%{gW}%-w%{.wb}%n %t%{-}%+w %=%{.w}'

activity "Activity in %t (%n)"

Gives you this.

I shamelessly stole this from someone on the Something Awful Forums.

Nested screen sessions rule

While it can quickly get a tad precarious, having a nested screen session is pretty damn cool.

Switching between them is pretty simple. ‘^a’ tells the terminal it’s a screen command. Simply hitting an additional ‘a’ tells it it’s the nested screen, and so on, depending on how many times you hit a (obviously, this would get too difficult to work with, hitting a five times just to send a command to a screen is a waste of everyones time). So, in this image, ‘^a a n’ would shift the nested screen to the next ‘tab’, and so on.

Distributing Common Lisp Code — Executables Say What?

One of the most common questions asked by those new to Lisp is how to make a nice, shiny executable. How do I make “Hello, World!” in Lisp like I have in C? I spent hours earlier today looking for various ways to package things, and it seems as though relying on our good old friend bash is the best solution, at least, if you’re dealing with the SBCL implementation of Common Lisp. I wrote this to be a nice little guide, so others don’t have to scour comp.lang.lisp themselves for answers.

We’ll start with a simple example doing everything manually, then script everything. “Hello, World!”, here we come! First off, let’s get some code going for hello.lisp. (bear with me here, this is a convoluted way to do Hello World in Lisp, however, it’ll make it easy to understand how to pull together larger applications)

hello.lisp

(format t "Hello, World!~%")

Looks innocent enough. But how do we run this guy now? The traditional way is to bust open an SBCL REPL, and either load/interpret the symbols, or compile it and run it from within SBCL; we’re going to do the latter.

dhcp223:~ ynadji$ sbcl* (compile-file "hello.lisp")
; compiling file "/Users/ynadji/hello.lisp" (written 15 OCT 2007 04:00:10 AM):
; compiling (FORMAT T ...)

; /Users/ynadji/hello.fasl written
; compilation finished in 0:00:00
#P"/Users/ynadji/hello.fasl"
NIL
NIL
* (load "hello.fasl")Hello, World!T

Sexy, our first Lisp program! But see how much of a pain it is to manually compile the file, then run it? Imagine this with several files with inter-dependencies! It’s difficult in Lisp to do what you would do in C, however, you can fake it with some very simple bash scripts and some elbow grease1.

The first step is to set up your files into packages, and handle those properly. I’m not going to describe Lisp packages in depth here, please see this for a more complete reference. The example I’m going to give is with a sudoku puzzle solver I wrote in Lisp. It’s quite horrendous Lisp code, but it’ll illustrate my point nonetheless. Below are the package definitions for the two files in this application:

config-parser.lisp

(defpackage :config-parser
            (:use :cl)
            (:export #:sudoku-config-parse)
            (:export #:sudoku-config-dump))

(provide :config-parser)
(in-package :config-parser)

and

sudoku.lisp

(defpackage :sudoku
            (:use :cl :config-parser)
            (:export #:backtracking))

(provide :sudoku)
(in-package :sudoku)

What’s important to note is that sudoku.lisp depends on config-parser.lisp and sudoku.lisp exports the function BACKTRACKING. We see this in the following steps, where we write our Makefile to take care of compilation and our bash script to run BACKTRACKING.

Makefile

all:
     sbcl --noinform --eval "(progn (compile-file \"config-parser.lisp\") (compile-file \"sudoku.lisp\") (quit))"

clean:
     rm -f *.fasl

SBCL allows you to pass in a form to evaluate. You see here I compile both files (in the correct order), then quit SBCL to drop me back down into my shell. Running ‘make all’ compiles both files and leaves me with two .fasl (compiled Lisp code)

dhcp223:~/Code/Lisp/sudoku ynadji$ makesbcl --noinform \
--eval "(progn (compile-file \"config-parser.lisp\") (compile-file \"sudoku.lisp\") (quit))";
compiling file "/Users/ynadji/Code/Lisp/sudoku/config-parser.lisp" (written 06 OCT 2007 01:55:55 PM):
;; (each function from config-parser.lisp is compiled here)
; /Users/ynadji/Code/Lisp/sudoku/config-parser.fasl written
; compiling file "/Users/ynadji/Code/Lisp/sudoku/sudoku.lisp" (written 15 OCT 2007 02:11:19 AM):
;; (each function from sudoku.lisp is compiled here)
; /Users/ynadji/Code/Lisp/sudoku/sudoku.fasl written;
compilation finished in 0:00:00

With this taken care of, now it’s time to write our bash script to execute everything. Using what we learned from in the compile phase, it’s easy to see the same logic (evaluating forms from the SBCL command-line) can execute our code as well as compile it.

sudoku.sh

#!/bin/bash

if [ $# -eq 0 ]
then
    echo "Usage ./sudoku.sh INPUT_PUZZLE [SOLUTION]"
else
    if [ $# -eq 1 ]
    then
        sbcl --noinform --load config-parser.fasl --load sudoku.fasl \
--eval "(progn (sudoku:backtracking \"$1\") (quit))"
    else
        sbcl --noinform --load config-parser.fasl --load sudoku.fasl --eval "(progn (sudoku:backtracking \"$1\" \"$2\") (quit))"
    fi
fi

The two fasls are loaded and this time, the evaluation uses the symbols compiled from our code. You notice it once again uses PROGN to sequentially evaluate what we want, then quit SBCL. If any errors are encountered, we get thrown into the SBCL debugger, but our code is perfect and doesn’t have that problem, right?

Empty Sudoku Puzzle: hard1.txt

2, ,1, , ,5, , ,
,6,7, , , , , ,8
8, , , ,6, , , ,
, ,9,6, , , ,1,
, ,8, ,7, ,3, ,
,3, , , ,1,4, ,
, , , ,9, , , ,3
7, , , , , ,6,8,
, , ,3, , ,5, ,1
dhcp223:~/Code/Lisp/sudoku ynadji$ ./sudoku.sh hard1.txt solution.txt
"Nodes expanded:" 39555
dhcp223:~/Code/Lisp/sudoku ynadji$

Solved Sudoku Puzzle: solution.txt

2,9,1,8,3,5,7,6,4
3,6,7,2,1,4,9,5,8
8,5,4,9,6,7,1,3,2
4,7,9,6,2,3,8,1,5
5,1,8,4,7,9,3,2,6
6,3,2,5,8,1,4,9,7
1,8,5,7,9,6,2,4,3
7,4,3,1,5,2,6,8,9
9,2,6,3,4,8,5,7,1

This sure beats fumbling around in SLiME every time I want to quickly solve a sudoku puzzle! If you’re interested in playing around with this yourself, I’ve posted my code (with Makefile/bash script) on my webspace for you to use. Most likely the included fasls won’t work on your machine, and you’ll have to recompile them for your version of SBCL, but that’s a simple ‘make’ command away :) .

Footnotes

1. I wanted to mention that something as simple as Hello World can be made into an executable with SB-EXECUTABLE, however, it’s difficult to use with larger programs and it does essentially the same thing, create a trampoline to launch your code through SBCL. For example:

dhcp223:~ ynadji$ sbcl
This is SBCL 1.0.9, an implementation of ANSI Common Lisp.
More information about SBCL is available at.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.

* (require 'sb-executable)

("SB-EXECUTABLE")* (compile-file "hello.lisp")

; compiling file "/Users/ynadji/hello.lisp" (written 15 OCT 2007 04:00:10 AM):
; compiling (FORMAT T ...)

; /Users/ynadji/hello.fasl written
; compilation finished in 0:00:00#P"/Users/ynadji/hello.fasl"
* (sb-executable:make-executable "hello" "hello.fasl")
* (quit)
dhcp223:~ ynadji$ ./hello Hello, World!

The problem with SB-EXECUTABLE is there isn’t a way (AFAIK) to create a trampoline with multiple fasls. And if there is, they sure as hell don’t make it easy to find. I’d recommend against it.

Follow

Get every new post delivered to your Inbox.