Wednesday, January 2, 2013

New Gazelle Stuff

The Select Button game jam is happening this month, and I want to use Gazelle to develop my entry. That means I needed the following features.

Multi-body Functions

define and lambda now support a multi-body syntax so that different patterns can be used to produce different effects. Consider:

(gazelle:essentials)

(define (vocalize [
         (([: :cat name])
          (+ name " says: meow"))
         (([: :dog name])
          (+ name " says: woof"))
        ]))

Then,

(vocalize [: :cat "Garfield"])

evaluates to:

"Garfield says: meow"

While

(vocalize [: :dog "Bowzer"])

to

"Bowzer says: woof"

The syntax is:

(define [(<argument-pattern1> body10 body1 ...)
         (<argument-pattern2> body20 body2 ...)
         ...])

Where each <argument-pattern> is a shadchen-style, array pattern with the array head removed.

Simple function definitions are still supported. I don't want to show the generated code because the pattern matcher generates large nested structures. I'm working on it, although some optimizations are in place for simple situations, like vectors of symbols with a symbol tail, etc. It should be possible to write a flat pattern matcher, but that is some work.

Macros support a similar interface. eg:

(define-macro let* [((nil (tail body)) (progn ,@body)) (((list (list symbol value) (tail binders)) (tail body)) (let ((,symbol ,value)) (let* ,binders ,@body)))])

Is an implementation of a let* like macro.

Self Recursion in Functions

Functions can recur to themselves using recur in tail positions. It is, at the moment, an unchecked error if recur occurs somewhere else. Given the underlying language implementation, it might be hard to check this statically. One can write filter like this, then:

(define (filter [
         ((fun [:] acc)
          acc)
         ((fun [: hd (tail tl)] acc)
          (if (fun hd)
              (recur fun tl (acc.concat [: hd]))
              (recur fun tl acc)))
          ]))

This sort of mock recursion doesn't grow the stack. Cute.

Changes to the define syntax apply to define+ as well.

I really need to use git more responsibly, all these changes, including lots of regressions, have been happening on the master branch, frequently updated on github. Sorry!

3 comments:

John Cowan said...

Why not change "recur" to "goto"? It would be both correct and traditional.

J.V. Toups said...

I believe that is a completely unfair dig, for at least one reason: recur can only `goto` one place, and is more like `re-enter`. That is it.

J.V. Toups said...

And, actually, now that you mention crazy control flow operations, what about this silly idea of `return`ing from a function? I rather like the functional approach where return value of a function must be one of its tails, but in Javascript you must literally mark the return value and you can return from any location whatever in the body. Recur is tame in comparison.