Archive for February, 2008

Fruit flies like a banana.

It appears my Windows box has given up the ghost. Now all I have to work with is three Mac machines:

  • key lime iBook clamshell, G3, 366 MHz, 576 Mb memory (~2001)
  • indigo iMac desktop, G3, 400 (?) MHz, 384 Mb memory (~2001)
  • MacBook, Intel Dual Core 2.0 GHz, 2 Gb memory (2007)

Funny, how things change.

(Well. I also have a small park of older computers, like my SGI O2, Commodore 64, Commodore Plus/4, etc… but those don’t count. (Although the idea of running Spiffy on the C64 and then talking to it using Firefox on the O2 sounds… wicked. :-)))

:: Comments off

Scheme crooks & nannies: the case form

You know R5RS’s case construct? It works much like case/switch statements in other languages, except it has more parentheses: ;-)

#;6> (define language 'chicken)
#;7> (case language
--->   ((c c++ java) "bleh")
--->   ((python perl ruby) "better")
--->   ((chicken scheme) "cool")
--->   (else "never heard of it"))
"cool"

Now, yesterday there was an interesting question in chicken-users. The following code works:

#;8> (define foo 'a)
#;9> (case foo
--->   ('a 3)
--->   (else 4))
3

Does that mean that Chicken’s case accepts qualifiers other than lists? Actually, no. Here’s a hint:

#;10> (define bar 'quote)
#;11> (case bar
---->   ('a 3)
---->   (else 4))
3

As it turns out, ‘a expands to (quote a), so it *is* a list, and therefore “correct”, in the sense that case treats it like a list containing the symbols quote and a. (Which is not what was intended, but it *is* valid.)

Too bad, the following does not work:

#;13> (define cool-names '(guido larry matz felix))
#;14> (case 'bill
---->   (cool-names "cool!")
---->   (else "uncool"))
Error: (map) during expansion of (case ...) -
 argument is not a proper list: cool-names

Inspecting a case construct with macroexpand-1 may give more insight in how case works exactly. I was going to leave this as an exercise to the reader, but thought better of it. :-) Here’s an example (formatting added by me):

#;1> (macroexpand-1 '(case a ((x y z) 5) (else 4)))
(let ((g2 a))
  (if (or (eqv? g2 (quote x))
          (eqv? g2 (quote y))
          (eqv? g2 (quote z)))
      (begin 5)
      (begin 4)))

:: Comments off

Patapon

This is a cute little game for the PSP… much recommended, if you like odd/unusual games, that is.

The game is highly rhythm-based. You control a small army of “Patapon” (basically creatures that look like eyes on legs) by drumming certain rhythms. For example, at the beginning of the game, the circle button is associated with the sound “pon”, and the square button with “pata” (hence the name of the game). Making your warriors advance is done by drumming the sound “pata-pata-pata-pon”, and you can make them attack by using “pon-pon-pata-pon”. As the game goes on, you get more rhythms and sounds, and gain special items.

I like this game… it reminds me a bit of Locoroco, even though they’re completely different.

[Update: Here's a demo video.]

:: Comments off

Learning Emacs, part 2.5

Just read this post: Switching editors is just as hard as switching languages. Fortunately my experiences with Emacs have been somewhat different. I was not looking forward to the steep learning curve, but to my surprise it only took a few days to get up to working speed. I’ve probably only scratched the surface of what’s possible, but I can use it without much problem for everyday Scheme hacking… and that was my intention.

To summarize it, here’s what helped me:

  • Read a decent book (as I mentioned before, I chose Learning GNU Emacs)
  • Remap keys to something more familiar, if you don’t want to use the funky C-this C-that combos for common actions; e.g. I use ⌘O to open a file, rather than C-x C-f; etc.
  • Study other people’s .emacs files. There’s a ton of them online. For example, here.
  • Take advantage of Emacs’ introspective features, like C-h k and C-h f, to quickly see what a key combination or function does.

Right now, the only thing that really bugs me is that Emacs still likes to recenter the screen every now and then, for no apparent reason… that drives me up the wall. A “feature” like that should not be enabled by default. But aside from that, I think it’s kind of an OK editor. ;-)

:: Comments (4)

Civ

Saw this preview of Civilization Revolution for Nintendo DS today. I’m most likely going to get it, as I’ve been playing Civ in various incarnations since 1992 or so.

I am wondering though, did anyone ever make an ASCII art version of Civ? E.g. something with the same rules, but ASCII graphics, kind of like Nethack. It would seem like a natural fit, with its grid-based map and turn-based movement. It’s by no means a *trivial* task of course, even without the graphics, but it seems doable.

(It would be an interesting project to do in Chicken, if I had a year to spare, or something… :-)

:: Comments off

Learning Emacs, part 2

More things I learned, after scraping together bits and pieces from all over the net:

  • Write a function that deletes the whole line, and bind it to a key (for some reason Emacs doesn’t have this out of the box):
    (defun delete-line ()
      "Kill the whole damn line."
      (interactive)
      (beginning-of-line)
      (kill-line 1)) ; delete line including newline 
    
    (global-set-key [(super y)] 'delete-line)
  • Resize the window so the minibuffer no longer hides behind the dock:
    (add-to-list ‘default-frame-alist ‘(height . 39))
  • When you scroll beyond the beginning or the end of the screen, Emacs has the annoying “feature” of re-centering the cursor. This turns it off (most of the time):
    (setq-default scroll-step 2)
  • Extend the Emacs load path so I can stick custom .el files in this directory and have them recognized by (require ‘foobar):
    (add-to-list ‘load-path “/Users/name/projects/scripts/macosx/emacs”)
  • Match parentheses automatically, always, not just when inserting them:
    (show-paren-mode)
  • Turn off the sound:
    (setq visible-bell t)
  • Turn off cursor blinking:
    (blink-cursor-mode nil)
  • When marking, always show the highlighted region:
    (transient-mark-mode t)
  • Show current column:
    (column-number-mode t)
  • Don’t use tabs for intending:
    (setq-default indent-tabs-mode nil)

I also added Quack to my .emacs file; let’s see how well it does when hacking Scheme.

Emacs more or less does what I want now. There are still a few things missing (like the ability to select things by moving the cursor while pressing Shift), but they’re not so important.

All in all, that wasn’t so bad. I expected it to take more time to get things up and running. Granted, I’ve looked at Emacs before (although I never really got around to using it), so I’m not *completely* new to it. The Learning GNU Emacs book was (and still is) a great help too; I found it much more useful than the built-in tutorial.

(Assuming I stay with Emacs, I will need to unlearn some vi-isms. I find myself pressing Esc a lot, or typing things like “i” or “dd”. :-)

:: Comments (3)

Learning Emacs, part 1

A few things I’ve learned since part 0:

  • Carbon Emacs does support Mac-style keybindings like ⌘Q, they just need to be activated. See Help -> Carbon Emacs Package -> Mac-Style Key Bindings.
  • I am now mapping Meta to Alt, as suggested (and demonstrated) in this comment. (Thanks Ozzi.)
  • I can set the Mac font using (set-default-font “-apple-monaco-medium-r-normal–13-140-72-72-m-140-mac-roman”). ^_^ Getting a list of available fonts is done using M-x set-default-font RET TAB TAB.
  • Good luck trying to look for “.emacs” in Google or any other search engine. Fortunately there’s such a thing as the dotemacs site, which offers a ton of example .emacs files.

Open issues:

  • I’m still trying to figure out how to resize the window automatically. Right now, when Emacs opens, the window is a little too big, and the bottom hides behind the dock.
    Update: Solved with (add-to-list ‘default-frame-alist ‘(height . 39)).
  • I’m still debating whether I should use the semi-default Mac-style key bindings, or define my own. I like ⌘O to map to C-x C-f, for example, but Carbon Emacs shows a dialog box. It appears I can either use the predefined key bindings, *or* map Super to ⌘ and define its key bindings myself, but not both.
  • I would like to select text by moving around with the cursor while pressing Shift… not sure if that can be done in Emacs.

:: Comments (1)

Python vs Scheme: function parameters (part III)

(Also see: part I, part II)

Just discovered something neat. In Python, if a function has arguments that have a default value, then those defaults are bound when the function is defined. So the following function, when called with no arguments, always returns the same value:

>>> def f(x=random.randrange(0, 100)): return x
...
>>> f()
32
>>> f()
32
>>> f()
32

…because the default value for x is determined when f is defined, rather than when it’s called.

And this is not allowed at all:

>>> def z(a, b=a): print a, b
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

I assumed that these rules would be the same in Chicken, but it turns out that this is not the case. This allows for some cool constructs that simply aren’t possible in Python. Like the example with the random number:

> (define (f #!optional (x (random 100))) x)
> (f)
23
> (f)
89
> (f)
97

It appears that (random 100) is computed whenever f is called, rather than when it’s defined. We can also refer to other arguments in this default expression:

> (define (g a #!optional (b (+ a 10)))
>   (list a b))
> (g 3)
(3 13)
> (g 40)
(40 50)

Good to know. This behavior is intentional rather than accidental, judging from the Extensions to the standard section in the user manual.

:: Comments (1)

Macro trial balloons

I’ve been hacking on and off on s1, my vaporware Awk-like tool that uses Scheme for scripting. The “language” defined by s1 includes a few macros. Strictly speaking, these are redundant, but they do make things shorter, which is important for writing one-liners.

Anyway, I am still kind of new to macros… so I’m wondering if the code I wrote is sound. I’m offering the definitions here for review. (Comments from experienced Schemers are welcome.)

1. inc! is used to easily increase variables. It can take any number of arguments; if none are given, 1 is added by default. For example:

  • (inc! x) adds 1 to x
  • (inc! x 33) adds 33 to x
  • (inc! x 1 2 3 4 5) adds (+ 1 2 3 4 5) to x

As the exclamation mark indicates, inc! changes the variable in-place. Here’s its current definition:

(define-macro (inc! name . args)
  (let ((total (gensym)))
    `(let ((,total
             (if (null? (list ,@args))
                 1
                 (apply + (list ,@args)))))
       (set! ,name (+ ,name ,total)))))

2. Defining multiple variables does not mix well with one-liners. So I added a macro def that allows one to define them quickly and concisely. Like inc!, def takes any number of arguments. If an argument is a list (name value), then a variable is created with the given name and value. If an argument is a symbol, then a variable is created with that name and a value of 0. (Awk is often used to add numbers, so zero seems the most sensible default, IMHO.)

Examples:

  • (def x) — same as (define x 0)
  • (def x y) — same as (define x 0) (define y 0)
  • (def (a 1) (b “hello”)) — same as (define a 1) (define b “hello”)
  • (def q (w 3)) — same as (define q 0) (define w 3)

Here’s the current definition:

(define-macro (def . args)
  (if (null? args)
      #f
      (let* ((a (car args))
             (rest-args (cdr args))
             (name (if (list? a) (car a) a))
             (value (if (list? a) (cadr a) 0)))
        `(begin
           (define ,name ,value)
           (def ,@rest-args)))))

(I’m not sure about the #f; it’s not supposed to return a value anyway.)

In any case, s1‘s auxiliary functions and macros allow for concise code. (Some of it is sloppy, but useful for “scripting”, especially one-liners. Naturally, it’s always possible to write longer scripts using “cleaner” code.)

For example, here’s a one-liner that takes the last words on the given lines and adds them up (assuming they are numbers):

s1 '(B (def s)) (inc! s &$nf) (A (out s))'

(I’m not sure about the & syntax yet; it’s used here as a shortcut for the as-number function, which attempts to convert a string to a number, returning 0 by default.)

B and A are shorthands for BEFORE and AFTER, blocks that are executed before and after the main code (which is executed for each line in the given text). The actual order in which these appear doesn’t matter, but it’s probably more intuitive to do before-main-after.

Print the number of lines, words and characters (like wc):

s1 '(B (def c w)) (inc! w nf) (inc! c (len $0) 1) (A (out nl w c))'

Print names starting with “Ga”:

s1 '(if (~ #/^Ga/) (print $0))' /usr/share/dict/propernames

(I’m using regex literals, and ~ is the same as string-search, except it matches against $0 (the whole line) by default.)

These are just teasers. Actual code is subject to change. I will release this when the “API” is somewhat stable. It’s still mostly a toy, though… :-)

:: Comments (4)

Learning Emacs, part 0

I am probably going to try and learn Emacs… or at least enough of it that I can use it for everyday Scheme editing. Learning GNU Emacs seems like a good start. The problem is more, finding a version for Mac OS X that does what I want (like recognizing my custom keybindings for Home/End, for example). Carbon Emacs seems to do at least that, unlike some other versions that I’ve found. (It has other issues though, like not recognizing common Apple key bindings like ⌘Q.) More about this later. In the meantime, I’m still using vim. :-)

(Unrelated: I just realized that “the problem is more” is probably a Dutch-ism… but I’ll keep using it anyway. :-)

:: Comments (6)

« Previous entries Next Page » Next Page »