Defining Function Arguments in Hy

Posted on April 22, 2013

Update: The syntax is likely to change soon. Apparently my update does not sit well with the Clojure folks and Hy has a strong precedent with Clojure syntax. So just consider this content “conceptual” until that is hammered out.

My patch to extend Hy’s function argument definitions has landed. It was merged in to Hy over the weekend so you’ll need to check out the master branch to follow along with this post. You can grab it here.

Lambda List Keywords

In lisp-like languages a function defines the arguments it receives using a regular-looking list like so:

(defun foo (a b c &rest xs)

This list is typically referred to in the CLHS as a lambda list. And that funny little symbol in there that begins with the ampersand? That’s called a lambda list keyword. They’re basically like markup for argument definitions.

I really pushed hard to add this feature to Hy because I’m a firm believer that explicit is better than implicit and lambda list keywords are very explicit.

In Hy we currently support three keywords: &rest, &key, and &kwargs. They map their arguments one-to-one with *args, foo=bar, and **kwargs respectively.

So now you can write a Hy function that looks like this:

(defn foo [x &key {bar "baz" answer 42} &kwargs kw]

(defn bar [x &rest xs]

Which will be equivalent to:

def foo(x, bar="baz", answer=42, **kw):

def bar(x, *xs):

Keep in mind that that the normal Python restrictions on argument definitions still apply. If you’re on 2.x then you cannot follow &rest with &key! It will work on Python 3.x but be aware that we’re not actually generating the AST for kwonlyargs which means that if you call foo with positional arguments that the positional parameters will be filled first before the varargs. I think that &optional should map to kwonlyargs which will fix this for Python 3 users. Of course, ideas and suggestions are welcome on this.

It is worth noting now that we haven’t figured out how to call functions using starargs or even with keywords yet. However you can use (the slightly ugly) KWAPPLY function:

(kwapply (foo "hello, world") {bar "foolius polonius"})

Which isn’t great but it’s a start!

If any of this is interesting to you then join us on on #hy and chat with us! Grab a checkout of Hy and contribute!