Using the Chez Scheme debugger

Achtung! Chez Scheme and Petite Chez Scheme do not give the same debugging information. Petite Chez Scheme is often much less helpful than Chez Scheme, and is probably half the reason why nobody actually tries debugging programs in Chez Scheme.

Here’s a sample, buggy program:

(define myreverse
  (lambda (ls)
    (if (null? ls)
      '()
      (append (myreverse (cdr ls)) (cons (car ls) '())))))

(define mylist (cons 1 (cons 2  (cons 3 (cons 4 5)))))

(display (myreverse mylist))

Let’s try loading it in Chez Scheme.

$ scheme
Chez Scheme Version 8.0
Copyright (c) 1985-2010 Cadence Research Systems

> (load "example.ss")
Exception in car: 5 is not a pair
Type (debug) to enter the debugger.
> 

Obviously, (debug) invokes the debugger. Once we get in there, however, it’s fairly cryptic.

debug> ?
Type i  to inspect the raise continuation (if available)
     s  to display the condition
     c  to inspect the condition
     e  or eof to exit the debugger, retaining error continuation
     q  to exit the debugger, discarding error continuation
debug>

Usually, inspecting the continuation is the most helpful thing to do, because once we’re in there, we can get a stack trace to find out where the error occurred. The command to print out the stack frames is sf.

debug> i
#<continuation in myreverse>                                      : sf
  0: #<continuation in myreverse>
  1: #<continuation in myreverse>
  2: #<continuation in myreverse>
  3: #<continuation in myreverse>
  4: #<continuation in myreverse>
  5: #<system continuation in map>
  6: #<system continuation in compile>
  7: #<system continuation>
  8: #<system continuation>
  9: #<system continuation in dynamic-wind>
  10: #<system continuation in dynamic-wind>
  11: #<system continuation in $reset-protect>
  12: #<system continuation in new-cafe>
#<continuation in myreverse>                                      : 

Knowing the stack trace, we can move down the stack frames using down, which is important if the debugger drops you in an error handler under the actual source of the problem. This information is often enough to debug your program. From here, we know that the error occurred when we were five instances deep in myreverse, so the problem was with the end of the list. But if you wanted more specifics, you can type s for show:

#<continuation in myreverse>                                      : s
  continuation:          #<continuation in myreverse>
  procedure code:        (lambda (ls) (if (null? ls) (quote ()) ...))
  call code:             (cdr ls)
  free variables:
  0. ls:                 5

Now we know for certain that we attempted (cdr ls) but ls was actually 5, and (cdr 5) is wrong.

Let’s try example2.ss:

(define pass-me-a-closure
  (lambda (thunk)
    (break)
    (thunk)))

(pass-me-a-closure
  (lambda ()
    (let loop ((x 5)
               (a 1))
      (if (zero? x)
        a
        (loop (sub1 x) (* a x))))))

Notice that we’ve set a breakpoint in the code using (break). This triggers the debugger, but only if we’re running Scheme interactively. If you try running scheme example2.ss directly, it will exit when it hits the breakpoint.

At the break point, we do the usual inspect and sfow frames.

[erjiang@silo ~]$ scheme
Chez Scheme Version 8.4
Copyright (c) 1985-2011 Cadence Research Systems

> (load "example2.ss")
break> i
#<continuation in pass-me-a-closure>                              : sf
  0: #<continuation in pass-me-a-closure>
  1: #<system continuation>
  2: #<system continuation>
  3: #<system continuation in dynamic-wind>
  4: #<system continuation in dynamic-wind>
  5: #<system continuation in $reset-protect>
  6: #<system continuation in new-cafe>
#<continuation in pass-me-a-closure>                              : s
  continuation:          #<system continuation>
  procedure code:        (lambda (thunk) (break) (display (thunk)))
  call code:             (break)
  free variables:
  0. thunk:              #<procedure>
#<continuation in pass-me-a-closure>                              : 

Right now, it doesn’t actually tell us what thunk is besides just #<procedure>. We need to rnspect that particular free variable by its number or name by issuing r 0 or r thunk and then printing the code.

#<continuation in pass-me-a-closure>                              : r 0
#<procedure>                                                      : c
(lambda () ((letrec ((loop (lambda (...) (...)))) loop) 5 1))     :

Notice that the let-loop form has been expanded (remember, the macro expander has already run) and on top of that, the part we actually care about has been elided. Also, the current object is now the code, instead of #<procedure>. Because of that, we can pretty-print the current object, and it will pretty-print the entire object.

(lambda () ((letrec ((loop (lambda (...) (...)))) loop) 5 1))     : p

(lambda ()
  ((letrec ([loop (lambda (x a)
                    (if (zero? x) a (loop (sub1 x) (* a x))))])
     loop)
    5
    1))

You can always go back up to the parent object from here.

In Chez Scheme, inspect is also available as a procedure that will launch the debugger and inspect whatever is passed to it. For example, writing (inspect thunk) into the above code would immediately launch the debugger on thunk. Likewise, doing (call/cc inspect) will launch the debugger and inspect the current continuation (which you can then trace).

Now you should know how to enter the debugger, inspect the stack frames, and inspect variables inside the stack frames, including the procedure code and call code. When in doubt, randomly hit keys or ask for help? Expect a pop quiz over this.

Arrow Endianness: How GNOME got sorting backwards

Conventions are important, even when it seems like it doesn’t matter one way or the other. Just look at all the people who complain about the nerve of Steve Jobs to place the close-window button on the left.

There’s no reason why the left side is better than the right side. Convention, however, says that you must choose one way and live with it, or else you’ll be forever forced to constantly convert between left-handed and right-handed traditions. Just ask anyone who’s ever had to write low-level networking code. When sending an integer, it doesn’t matter whether the big end or little end goes first, but if you don’t agree with the other party, your message will come out garbled.

So imagine my discomfort when I have to sort files in Nautilus or sort processes in System Monitor.

Continue reading Arrow Endianness: How GNOME got sorting backwards

Venturer HPS9308 GPS navigation system

If you ever want to modify or upgrade your Venturer HPS9308 GPS navigation system, you can easily do so by modifying or replacing the software on the SD Card. However, there are some settings that aren’t obvious and aren’t directly modifiable, so you have to follow a couple things.

It seems like the default Venturer shell, when you choose “Navigation”, looks for SDCard\MobileNavigator\MobileNavigator.exe and runs it. Thus, if you want to replace the software that gets run, you should place the executable at that path. In addition, the GPS device is on port 1 with a baud rate of 4800, at least according to a working config file I found. For reference, that was in SDCard\MobileNavigator\sys.txt with the section
[gps]
port="1"
baud="4800"

Gaming hasn’t changed

This is about an essay I wrote a couple years back about gaming, under the theme of work and play, and it’s about how video games are just a subset of gaming, and how they conceptually fit within philosophical frameworks established in the mid-20th century. Among other things, it goes into why World of Warcraft directly maps onto the four categories of games set forth by Roger Caillois in 1958: Agôn, alea, mimicry, and ilinx, which could be described as competition, chance, role-playing, and thrill.

It’s not a perfect paper and gamers might roll their eyes at reading a description of what an MMO is. There are surely some things that I would revise if I had the chance, but the version presented here is untouched from my original, save for formatting. It’s not a journal paper nor is it a book review, but I hope that some find it interesting. There is a lot that has been written on this subject, and there is much more that could be written. This is just a piece towards the theory that the core components of a fun game are readily identifiable and, with that knowledge, anybody can assemble a fun game.

Some quotes from the paper
Profit Versus Play: Business and Gaming in MMOs (application/pdf, 87 KB):

On whether MMOs qualify as games in a traditional sense:

David Golumbia, who is incidentally among such de-
tractors, could not examine this issue without first defin-
ing the French word jeu in the context of Jacques Der-
rida’s deconstruction of “play.” Fundamentally, Golumbia
establishes jeu as both “play” and “games” (and not con-
trivances like “freeplay”) and this paper will assume the
same: that “games” and “play” are merely different parts
of speech referring to the same concept without carry-
ing any intrinsic differences. And, as we’ll see, MMOs
like Ultima Online and EverQuest are certainly games in
the traditional sense as they fit like clockwork into Roger
Caillois’ categorization of games.

On the never-perfect divide between game and real:

This “contagion of reality” that plagues MMOs has
been and will continue to be money. “The minute you
hardwire constraints into a virtual world, an economy
emerges,” explained Castronova to Wired. “One-trillionth
of a second later, that economy starts interacting with
ours.”

And on harnessing Nietzschean behaviors:

It’s this type of accumulating points system that
Golumbia described as an exploitation of Machtelgust, or
the “lust for power” from Nietzsche’s writings. Golumbia
colored computer games in general as being deceptively
simplistic and degenerate. A single-player first-person
shooter (FPS) like the classic sci-fi game Half-life, while
appearing to offer freedom and a story to the player, is re-
ally a very rigid, pre-scripted experience of just shooting
anything that moves with a superficial and shallow plot
tacked on. Likewise, he wrote, MMORPGs are mostly
single-player experiences, despite the name, filled with
repetitive quests in a “surprisingly rigid, uncompromis-
ing, and even authoritarian” world.

HTML <legend> tag is broken in WebKit

All I wanted was for a legend tag to fill up its box horizontally, much like an h1 or div does by default. Apparently, legend tags are special and don’t follow the same rules as other tags in WebKit, and what I wanted to do was simply impossible. Since I wasn’t the one to choose to use the legend tag (it’s a CakePHP default), I simply replaced all instances of it with <div class="legend"> and went on with life.

Here’s an example in which the same display: block style is applied to an h3, a span, and a legend tag, each sitting in identical divs.

Gecko renders the legend tag as a block element correctly, and it fills up the div.

WebKit does something special about the width, and so it fails to fill up the div.

Given WebKit’s lineage, it’s not surprising that KHTML does even worse at the exercise.

Try it for yourself: legend width js-fiddle. Other people have had similar issues as well: StackOverflow: Cannot add margin to Legend element in Safari & Chrome.