2013/02/23
Land of Lisp on Gauche
I've been working on translating Conrad Barski's "Land of Lisp" to Japanese, and it finally hit the bookstores in Japan (published from O'Reilly Japan). To celebrate that, I ported the code in the book to Gauche.
Since Gauche adopts quite a few Common Lisp idioms, the port is pretty straightforward. The code may serve as an example to show how to translate CL-style code into Gauche.
Here are some observations.
- Most of CL's
loop
use cases can be written using srfi:42.- The trick is that, in CL, you think "OK, I loop over this (list, vector,
integer, etc.) and I want to get this (list, sum, etc.)", while
in srfi-42, you first think what you want (ok, I want list so I use
list-ec
/ ok, I want to stop iteration when any of the element satisfies the condition, so I useany?-ec
), then you think about what to iterate.
- The trick is that, in CL, you think "OK, I loop over this (list, vector,
integer, etc.) and I want to get this (list, sum, etc.)", while
in srfi-42, you first think what you want (ok, I want list so I use
- CL has many idioms that take advantage of () being boolean false, and
car
/cdr
ofnil
is stillnil
. It is not a good idea to carry over that idiom to Scheme, or you'll be frustrated feeling that Scheme's distinction of#f
and()
gets in your way. It just needs a different mindset (complaining about it is like a C programmer complaining 0 isn't false in some languages).- For example, in CL, you can access to the value associated to the key
in alist by the following code, without worrying the case when key isn't
found:
(cdr (assoc key alist))
You'll be annoyed that in Scheme, assoc returns#f
when key isn't found, andcdr
barfs. In Gauche, recommended way is as follows:(assoc-ref alist key :optional default)
- Another common CL idiom is to build a list conditionally:
(append (list up down) (unless (zerop (mod pos *board-size*)) (list (1- up) (1- pos))) (unless (zerop (mod (1+ pos) *board-size*)) (list (1+ pos) (1+ down))))
This idiom uses the fact thatunless
returnsnil
when the condition is satisfied. In Gauche,unless
returns#<undef>
so this doesn't work. Instead of falling back to more verboseif
, you can usecond-list
.(cond-list [#t @ (list up down)] [(not (zero? (mod pos *board-size*))) @ (list (- up 1) (- pos 1))] [(not (zero? (mod (+ pos 1) *board-size*))) @ (list (+ pos 1) (+ down 1))])
- For example, in CL, you can access to the value associated to the key
in alist by the following code, without worrying the case when key isn't
found:
- The lazy evaluation stuff built in Chapter 18 (
lazy.lisp
) comes free in Gauche, asutil.stream
module. Thelazy.scm
file in Gauche version only shows the correspondence of two APIs. - I have a plan to make
format
CL-compatible. It's not done yet, so I had to rewrite some code using advanced formatting directives with the plain Scheme code. - The CL's
defstruct
code is translated todefine-record-type
straightforwardly, except that our record type can't set the default value when the constructor argument is omitted. (R6RS records can do that using protocol. I prefer easier way, though.)
Tag: CommonLisp
Post a comment