Monday, June 20, 2011

A Brief Intro to Writing Macros in Racket

I plan to learn, among other things, more about lisp-like macros this Summer. I had a brief introduction to the Common Lisp macro system years ago, but was frightened away when I couldn't understand my code after taking a few days' break. I'm revisiting macros using Racket. While there are a handful of great references on Common Lisp macros (including Paul Graham's On Lisp, which I've yet to read!), I had trouble finding a basic introduction to Racket's more complicated macro system. The team at Racket/PLT Scheme have been researching macro systems for a few years now, and they've implemented a pretty sophisticated system: syntax objects are first class citizens, et cetera. Quite honestly, I don't understand any of it yet. But I thought it'd help to write down my thoughts and work thus far. Maybe it'll help someone else learn something, too!

Step 1: Getting to terms with Syntax Objects and Transformer Bindings


Lisp macros allow you to extend the syntax of the lisp language itself. Racket implements these macros by creating a syntax type to model the syntax you wish to implement. Essentially, a syntax object contains an unevaluated s-expression (lisp expression) along with some data about its scope. A syntax object is a first-class citizen, meaning it can be passed around to and fro functions like any other lisp object. You can extract data (e.g. particular symbols) from these syntax objects using pattern matching techniques, and then use that data to build a new syntax object. Id est, you can write a function that takes a syntax object and returns a new, transformed syntax object. To implement a macro, you describe the syntax and write a function to transform it. When Racket sees your new syntax, it transforms it as you described and then evaluates the resulting syntax object as an s-expression within its own scope. (At least, I think that's what happens!)

Pretend for a second that we wish to implement a while clause in Racket. We want to be able to write something like:
(while (< x 5)
    (begin (display x)
        (set! x (+ x 1))))

And have it display
1234

What we need is something to take the above s-expression and transform it into the following s-expression:
(define (loop)
    (if (< x 5)
        (begin
            (display x)
            (set! x (+ 1 x))
            (loop)
        )
        (display "")))
(loop)

Let's first think about how to turn the s-expression (while test body) into a syntax object. This is done with the syntax function, e.g.:
(syntax (while text body))

Racket provides a shortcut to "quote" syntax, id est, the above is equivalent to:
#`(while text body)

Let's go ahead and define a syntax object to use later in our examples:
(define stx #`(while (< x 5)
    (begin (display x)
        (set! x (+ x 1))
    )
))

But how do we transform this syntax object into another? As stated above, we'll use a sort of pattern matching to extract data from the syntax object, and plug this data into a new syntax template. Racket provides a function to implement this called syntax-case. syntax-case is a function that takes a syntax object, a list of "keywords", and a list of pairs of patterns and new syntax objects. It tries to match the syntax object you provided to one of the patterns listed, and returns the new corresponding syntax object. Those patterns can be tricky, and are best explained with examples, so let's try one: First note that our keyword is "while", let's try the code:
(syntax-case stx
    (while)
    [(while test body) #`body])

The (while test body) says that we're looking for an s-expression that starts with the keyword "while", and follows with two other s-expressions. It binds the syntax object corresponding to those s-expressions to the symbols "test" and "body", respectively. The new syntax object #`body is simply the body sample. Thus the above expression returns a syntax object for only the last s-expression in our while clause.

If we didn't list "while" in our keyword list, the expression would have still returned the same result. But instead of only matching while-clauses, the syntax-case expression would match anything, and simply store the first expression in a symbol named while.

Let's implement a proper transformation now. As we stated above, we want our while expression to transform into a recursive function that calls itself so long as test is true. Our syntax-case is thus:
(syntax-case stx (while)
    [(while test body)
    #`(begin (define (loop)
            (if test
                (begin body
                    (loop))
                (display "")))
        (loop))])

As you can [hopefully] see if you run this code through a REPL, we get a syntax object containing something similar to our desired s-expression. Now let's tell Racket to perform this syntax transformation. To do this, we'll use define-syntax. This statement works a lot like our normal define, except that it ties an identifier to a syntax transformation. Here's the code:
(define-syntax (while stx-obj)
    (syntax-case stx-obj (while)
        [(while test body)
        #`(begin (define (loop)
                (if test
                    (begin body
                        (loop))
                    (display "")))
            (loop))]))

Now the code
(let ((x 1))
    (while (< x 5)
        (begin (display x)
            (set! x (+ 1 x)))))

Works as expected. stx-obj captures the total expression, including the while clause that we defined. Since Racket detects this by itself, we actually don't need to define the while keyword. We can replace it with an empty keyword list and a "_" (underscore) pattern (this matches any syntax symbol, but doesn't bind the symbol to a new expression) like this:
(define-syntax (while stx-obj)
    (syntax-case stx-obj ()
        [(_ test body)
        #`(begin (define (loop)
                (if test
                    (begin body
                        (loop))
                    (display "")))
            (loop))]))


Rolling Our Own Object System


Now that we've got the basics of macros down, let's try a slightly more ambitious project: we're going to use macros to implement a basic message-passing object system. First, consider the following code:
(define (animal location health speed)
    (define (move new-loc)
        (set! location new-loc)
        (set! health (- health speed)))
    (define (dispatch m)
        (cond [(eq? m 'move) move]
            [(eq? m 'location) location]
            [(eq? m 'health) health]
            [(eq? m 'speed) speed]
            (else (error "unknown message"))))
    dispatch)

(define my-animal (animal 1 100 5))
(my-animal 'health)

     >> 100

((my-animal `move) 2)
(my-animal 'health)

     >> 95

This code implements a message-passing design pattern for my awkward model of an "animal" (perhaps for a game?). We can create new animal objects with the animal function that we defined, and then pass messages to it, emulating object-oriented programming.

Instead of writing this design pattern over and over again, we're going to create a macro to implement it for us. We want to write
(new-object Animal
    (location health speed)
    [(move (λ (new-loc)
        (set! location new-loc)
        (set! health (- health speed))))])

The pattern we wish to match is:
(_ name (value ...) [(func-name lambda-body) ...])

The ellipses (...) after "value" and "(func-name lambda-body)" denote that we expect a list of symbols, rather than just a single symbol. When we write the syntax template, we'll have to use the same ellipses to repeat the corresponding expression across the list. To transform the above code into our implementation, the code is:
#'(define (name value ...)
    (define func-name lambda-body) ...
    (define (dispatch m)
        (cond [(eq? m 'value) value] ...
            [(eq? m 'func-name) func-name] ...
            [else (error "unknown message")]))
    dispatch)

Combining all this together, we can write the following syntax transformation:
(define-syntax (new-object stx)
    (syntax-case stx ()
        [(_ name (value ...) [(func-name lambda-body) ...])
            #'(define (name value ...)
                (define func-name lambda-body) ...
                (define (dispatch m)
                    (cond [(eq? m 'value) value] ...
                        [(eq? m 'func-name) func-name] ...
                        [else (error "unknown message")]))
                dispatch)]))

This macro works fine for the above. But hold on! What if we want to implement setters for new objects? E.g.
((my-animal `set-health!) 500)

Implementing this bit is tricky...

Manipulating Syntax


...to do this, we'll need to take the syntax object for the symbol "health" and transform it into a new syntax object that contains the symbol "set-health!". We'll need to do this for the full list of members. But how can we? Let's take a break from the macros and play around with syntax objects for a bit. First, define the following:
(define stx #'(health location speed))
(syntax->list stx)

syntax->list does what it sounds like, takes a syntax object of a list and returns a list of syntax objects. Our idea is to continue transformations on that list until it becomes the following syntax object list:
#'(set-health! set-location! set-speed!)

Then we'll incorporate it into our macro definition. Racket provides another useful function, syntax->datum which will transform each individual syntax object of a symbol into the symbol itself. So our next step is
(map syntax->datum (syntax->list stx))

Now we have a list of symbols. We can transform this normally, e.g.
(map (λ (item)
        (format "set-~a!" (syntax->datum item)))
    (syntax->list stx))

We're getting closer, now we need to transform this list of strings back into a list of syntax objects of symbols. This is pretty straightforward, we just nest datum->syntax and string->symbol. Note the following about datum->syntax: A syntax object includes information about the scope of the s-expression it contains. We want our new syntax object to be within the same scope as the original syntax object. Luckily, datum->syntax will do exactly that. It takes both a syntax object and a symbol and returns a new syntax object containing that symbol within the scope of the first syntax object. Hence our code is
(map (λ (item)
        (datum->syntax stx
                (string->symbol (format "set-~a!" (syntax->datum item)))))
    (syntax->list stx))

That does exactly what we want it to. Now, let's re-visit the syntax template from our macro and see how to implement this idea for the object setters. Recall the macro:
(define-syntax (new-object stx)
    (syntax-case stx ()
        [(_ name (value ...) [(func-name lambda-body) ...])
            #'(define (name value ...)
                (define func-name lambda-body) ...
                (define (dispatch m)
                    (cond [(eq? m 'value) value] ...
                        [(eq? m 'func-name) func-name] ...
                        [else (error "unknown message")]))
                dispatch)]))

We need to do an intermediate syntax transformation, to convert the "(values ...)" syntax object to the one we created earlier. We can do this with with-syntax. with-syntax takes a list of pairs of patterns and syntax objects and a template syntax object. It binds the bits of the syntax object to the symbols in the pattern, likesyntax-case, and transforms the template into a new syntax object. We're going to match our transformed list to a simple syntax pattern like thus
[(set-value ...)
    (map (λ (item)
        (datum->syntax stx
            (string->symbol (format "set-~a!" (syntax->datum item)))))
        (syntax->list #`(value ...)))]

Note that syntax->list is now acting on #`(value ...), id est, the syntax object of lists of symbols for object member names. Also note that the syntax object used in datum->syntax is the stx object from our macro definition. Our new template, with the new setters, looks like:
#'(define (name value ...)
    (define (set-value new-val)
        (set! value new-val)) ...
    (define func-name lambda-body) ...
    (define (dispatch m)
        (cond [(eq? m 'value) value] ...
            [(eq? m 'func-name) func-name] ...
            [(eq? m 'set-value) set-value] ...
            [else (error "unknown message")]))
    dispatch)

Now let's wrap it all up in our macro definition:
(define-syntax (new-object stx)
    (syntax-case stx ()
        [(_ name (value ...) [(func-name lambda-body) ...])
        (with-syntax ([(set-value ...)
                (map (λ (item)
                    (datum->syntax stx
                        (string->symbol (format "set-~a!" (syntax->datum item)))))
                    (syntax->list #`(value ...)))])
        #'(define (name value ...)
            (define (set-value new-val)
                (set! value new-val)) ...
            (define func-name lambda-body) ...
            (define (dispatch m)
                (cond [(eq? m 'value) value] ...
                    [(eq? m 'func-name) func-name] ...
                    [(eq? m 'set-value) set-value] ...
                    [else (error "unknown message")]))
                dispatch))]))

There you have it, folks. We've implemented a basic object system in less than 20 lines of code.

Comments, questions, corrections all welcome.

Saturday, June 4, 2011

CSS3 Transition Effects in My New Website

Having finished my MSci exams at UCL, I thought I would take this opportunity to "freshen up" the layout on my personal website. There was one nasty, looming problem with this idea, however - I suck at design.

Design work starts off a days-long cycle of me torturing myself. In stage 1, I accept/realize that I am bad designer with few capabilities and resign myself to "keeping it simple". Stage 2 sees me drawing half of a dozen paper sketches and mock-ups for this "simple design". These designs later inundate my hapless friends as I pester them for their opinions. By stage 3, I've accepted that half of my sketches are terrible, and that the other half require an on-screen mockup to judge. Thus I launch the Gimp and try to create a vector mockup, leading back to stage 1: realizing that I don't have the technical prowess to complete this design and resolving to do something simpler. After several days, this process takes its toll on my mental health and produces an unremarkable HTML product.

I went through this cycle this week (after promising myself that "freshening up" would only take a few hours) and settled on a design similar to my Reverse Job App awhile back. But when I began writing the actual HTML I decided I could torture myself a little more and complete the layout without any use of javascript or jquery. Instead, I relied solely on the new CSS3 gradient and transition effects. I decided to write this blog about the latter effect.

The CSS Effect



The front landing page of my has three boxes that link to the different sections of my website like such:



Each box has a neat hover effect where the shaded background drops down and changes color. While this effect is easy to implement in jquery, I was able to implement it in Firefox/Chrome/Safari without using one lick of javascript, and I'll show you how.

The HTML



< a href="http://www.blogger.com/maths" >
< div class="bg" >
<div class="filter" >
< p >maths. < /p >
< /div >
< /div >
< /a >


Two divs in an a tag? That's right. The top a tag is obviously the link. The outer div.bg tag gives us the background images and adjusts the size of the a element (this is possible without the div.bg, but I could only get the full background image to show if I used absolute positioning). The inner div.filter tag and p tag will be the subject of the transition effects. div.filter is a partially transparent box that gives us the shaded background. The p tag is the actual text of the link.

CSS Before Effects



Let's implement the above description.


* {margin:0; padding:0;}
a{
width:180px;
text-decoration: none;
}
a > div.bg {
height:216px;
width:180px;
border: 2px solid black;
background-image: url(maths.png);
}
a > div.bg > div.filter{
background-color: rgba(33, 33, 33, 0.5);
height:217px;
width:180px;
}
a > div.bg > div.filter > p{
display:block;
padding-top:90px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
}


All pretty straightforward. Combining the above should yield a pretty simple website:



Now let's write down the CSS for the hover stage. We'll start by adjusting the above CSS to get an a tag with a darker filter that only covers the top of the image. This means we need to change the css for div.filter and p.


a > div.bg > div.filter
{
background-color:#000000;
background-color: rgba(0, 0, 0, 0.7);
height:145px;
margin-top:72px;
}
a > div.bg > div.filter > p{
display:block;
padding-top:18px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
text-decoration:underline;
}


How do we get a hover effect? That's simple, we can combine these two descriptions using the :hover psuedo class. We'll use the first CSS we wrote, and append the second definitions after changing "a > " to "a:hover >", like so:


* {margin:0; padding:0;}
a{
width:180px;
text-decoration: none;
}
a > div.bg {
height:216px;
width:180px;
border: 2px solid black;
background-image: url(maths.png);
}
a > div.bg > div.filter{
background-color: rgba(33, 33, 33, 0.5);
height:217px;
width:180px;
}
a > div.bg > div.filter > p{
display:block;
padding-top:90px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
}
a:hover > div.bg > div.filter
{
background-color:#000000;
background-color: rgba(0, 0, 0, 0.7);
height:145px;
margin-top:72px;
}
a:hover > div.bg > div.filter > p{
display:block;
padding-top:18px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
text-decoration:underline;
}




CSS Transition Effects



We're nearly there! How do we get those cool transitions? The working draft for CSS3 provides two new attributes:


transition-property: [list of properties]
transition-duration: [number of seconds]


transition-property instructs the browser to do a default (read: linear) transition from the previous properties to the new properties in this definition. transition-duration is just the number of seconds the effect should last. You can read more about them at the Mozilla Development Network.

For div.filter, we're changing the background color, the height, and the margin-top, so we change the hover div.filter definition to:


a:hover > div.bg > div.filter
{
background-color:#000000;
background-color: rgba(0, 0, 0, 0.7);
height:145px;
margin-top:72px;
transition-property: background-color, height,margin-top;
transition-duration: 0.3s;
}


We'll want to add the same thing to the default div.filter definition as well, so we have a smooth transition from hover to non-hover states:


a > div.bg > div.filter{
background-color: rgba(33, 33, 33, 0.5);
height:217px;
width:180px;
transition-property: background-color, height,margin-top;
transition-duration: 0.3s;
}


Similarly, we need to change the padding-top property of the p tag, this is done with:


a:hover > div.bg > div.filter > p{
display:block;
transition-property:padding-top;
transition-duration: 0.3s;
padding-top:18px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
text-decoration:underline;
}


But hold on! Since transition-property, et al, is still experimental, it requires a vender-prefix. E.g. for Firefox, it needs -moz-transition-property, et cetera, for webkit-based browsers, -webkit-, for opera, -o-. So our complete CSS is:


* {margin:0; padding:0;}
a{
width:180px;
text-decoration: none;
}
a > div.bg {
height:216px;
width:180px;
border: 2px solid black;
background-image: url(maths.png);
}

a > div.bg > div.filter
{
float: left;
background-color: transparent;
background-color: rgba(33, 33, 33, 0.5);
height:217px;
width:180px;
-moz-transition-property: background-color, height,margin-top;
-moz-transition-duration: 0.3s;
-webkit-transition-property: background-color, height,margin-top;
-webkit-transition-duration: 0.3s;
-o-transition-property: background-color, height,margin-top;
-o-transition-duration: 0.3s;

}
a > div.bg > div.filter > p{
display:block;
padding-top:90px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
}
a:hover > div.bg > div.filter
{
background-color:#000000;
background-color: rgba(0, 0, 0, 0.7);
height:145px;
margin-top:72px;
-moz-transition-property: background-color, height,margin-top;
-moz-transition-duration: 0.3s;
-webkit-transition-property: background-color, height,margin-top;
-webkit-transition-duration: 0.3s;
-o-transition-property: background-color, height,margin-top;
-o-transition-duration: 0.3s;
}
a:hover > div.bg > div.filter > p{
padding-top:18px;
padding-left:18px;
font-weight:bold;
color: #ffffff;
text-decoration:underline;
-moz-transition-property:padding-top;
-moz-transition-duration: 0.3s;
-webkit-transition-property: padding-top;
-webkit-transition-duration: 0.3s;
-o-transition-property: padding-top;
-o-transition-duration: 0.3s;
}


There you have it, folks! CSS3 transitions for everyone! (except, possibly, IE users.)