Archive for December, 2007

Scheme’s funky ‘let’ loop

In my previous post, I used this construct to loop for *max-iterations*:

(let loop ((i 0))
    (unless (= i *max-iterations*)
        (fac 30)
        (loop (+ i 1))))

This useful idiom is called a named let. The let special form is not intended for looping, but can be used for that purpose by calling the name (in this case, loop) recursively. Note that loop is just a name rather than a Scheme keyword or built-in function or form. We could give the loop any name.

I had actually forgotten about this form until I saw it again in a newsgroup post. By comparison, the “normal” let looks like this:

(let ((name1 value1)
      (name2 value2)
      ...etc...)
   ...body...)

The named let doesn’t use as much magic as you might think, since it’s basically a shorthand for a letrec with a lambda.

:: Comments off

Compiling Chicken code (part II)

One of the cool features of Chicken is that you may choose to compile parts of your Scheme program to C, in order to get better performance.

Let’s write a (naive) implementation of the factorial function. Store it in fac.scm:

;; fac.scm

(define (fac n)
(if (<= n 1)
1
(* n (fac (- n 1)))))

Now, write a second file main.scm that uses our fac function. Normally this would be as simple as

(load "fac")

(print (fac 30))

But I’d like to include some simple benchmark code, to see how well fac performs, interpreted vs compiled. I’m using the following code to call (fac 30) 100,000 times, and time the results.

;; main.scm

(load "fac")

(define *max-iterations* 100000)

(define t1 (current-milliseconds))
(let loop ((i 0))
(unless (= i *max-iterations*)
(fac 30)
(loop (+ i 1))))
(define t2 (current-milliseconds))

(define seconds (/ (- t2 t1) 1000))
(printf "~a iterations in ~a seconds.~n" *max-iterations* seconds)

Interpreted, it takes a little more than two seconds on my machine:

$ csi -s main.scm
100000 iterations in 2.191 seconds.

We can do better than that. Let’s compile fac.scm and see if it makes a difference.

$ csc -s fac.scm  # produces fac.so
$ csi -s main.scm
100000 iterations in 0.326 seconds.

That’s right — we still run main.scm interpreted, but it now uses the *compiled* fac.scm, which makes execution much faster. ^_^

We could do a lot more with this, e.g. compile main.scm to an executable, etc, but I just wanted to demonstrate how easy it is to precompile libraries, with no change in code. (At least, not for simple cases like this… but that’s a different story.)

:: Comments (2)

Compiling Chicken code (part I)

(This post is just a quick introduction to using the Chicken compiler and interpreter.)

Consider this simple file:

;; hello.scm

(print "Hello, world!")

Save this as hello.scm.

Running this as a script in the interpreter is done as follows:

$ csi -s hello.scm

Note that if the -s is omitted, the script will still run, after which the interactive interpreter is started. This can be useful in some situations (e.g. to do post-execution inspection).

Alternatively, we may choose to compile the script to an executable:

$ csc hello.scm

(csc has a lot of options, but the simplest case does what most people would expect, i.e. it compiles an the executable named hello.)

Lo and behold, it works:

$ ./hello
Hello, world!

On my system (using Chicken 2.732, Mac OS X 10.4, Intel Dual Core) this produces a 14K executable, which seems quite reasonable. However, the way I understand it, this file dynamically links to the Chicken libraries. To create a standalone executable, we must use the -static command line option, which produces a much bigger file:

$ csc -static hello.scm
$ ls -l hello
-rwxr-xr-x   1 zephyrfa  zephyrfa  1370732 Dec 30 13:54 hello*

By the way, I’m not entirely sure that this really produces an executable that is 100% standalone… I’ll have to do more testing.

There is much, much more to the Chicken compiler. Expect to see more about it in future posts. (Like the next one… :-)

:: Comments off

Cool listcomp

Check this post, which demonstrates the power of Haskell’s list comprehensions:

f :: Int -> [ (Int, Int, Int) ]

f n = [ (x, y, z) |
x <- [ 1 .. n ],
y <- [ x+1 .. n ],
z <- [ y+1 .. n ],
(x * x) + (y * y) == (z * z) ]

I first thought there was some special magic going on, like maybe some Prolog-like matching, but then I realized that you can do the same in Python:

def f(n):
    return [(x,y,z)
            for x in range(1, n+1)
            for y in range(x+1, n+1)
            for z in range(y+1, n+1)
            if x*x + y*y == z*z]
print f(20)

(Which isn’t so surprising after all, as Python “borrowed” list comprehensions from Haskell… but still.)

:: Comments off

I’m getting old.

Stuff like this just ticks me off: Ruby – best introductory programming language. Not because Ruby wouldn’t make a good starter language, but rather because all the arguments that the article makes in favor of Ruby, apply equally well to Python, which has been around longer. So my first reaction to seeing articles like this is, “why not Python?”

(Just to make things clear: This is not an attempt to slam the author of the article; actually, I find the blog interesting and thought-inspiring, and just added it to my Bloglines today.)

I must admit that I do hold a bit of a grudge against those who ignored Python for years and now tout the benefits of Ruby, pointing to Ruby features that Python has had for ages. (You know. Everything is an object. Interactive interpreter. Changing objects on the fly. Etc.)

Of course, there might be good reasons for that, but I suspect that in many cases, the reasons for not choosing Python were superficial. It’s that weird whitespace language. Or maybe its object model doesn’t look like Java’s.

There was a time that there was much talk about how Python would make a great introductory language, how it could be taught to kids, and how it made programming fun again. These days, we’re hearing that again, but now it’s Ruby instead of Python. (Although there are exceptions. :-) What bothers me here is not that Ruby wouldn’t be a good choice, but that everybody suddenly has forgotten about Python, like it’s not a contender at all anymore.

Maybe we’re now getting a taste of how Lispers have felt for years, or maybe decades. (Then again, Lisp syntax isn’t exactly friendly to newbies or kids, is it?)

:: Comments off

A resolution for 2008

You know how they say that in order to improve yourself as a programmer, it’s a good idea to learn a new language each year? Well, I feel that I haven’t been learning much for the last few years. In fact, I’ve been stagnant for quite a while.

So, maybe I should make a change for 2008, and devote it to learning. The language I chose for this is Scheme. Chicken Scheme, to be precise. (I chose a Lisp language because it’s a step up from Python and likely to challenge me in many ways; Scheme because it’s clean; and Chicken because it seems to be more of a pragmatic/practical Scheme variant, rather than being focused on theory.)

I tinkered with Chicken before, but I didn’t really get very far, possibly because I chose a project that felt like a dead end. But there is much, much to learn. I want to learn about Scheme macros, and continuations, and SRFIs, and object models, and eggs, and interfacing with C code, and many other things. I want to study SICP and EOPL and HTDP. And most importantly, I want to use Scheme much like I use Python now, in a way that produces readable, understandable and maintainable code.

In this blog, I’m hoping to record my progress, talk about things I learned (or that stump me), compare Scheme to other languages (most importantly Python), etc. Hopefully, while I’m at it, I’ll also produce some code. :-)

(That said, this blog won’t be *exclusively* about my adventures with Scheme…)

:: Comments off

Hello world!

First post! Test test…

 (define (hello-world)
     (print "Hello, world!"))

:: Comments (1)