Hy has lots of little features that I often forget to use. This post is about destructuring and I hope that after writing about it a bit, I’ll remember it in the future. Incidentally, this came up while I was working with new AI routines for rats.
But lets start with the canonical example how to swap values of two variables:
=> (setv a 5) => (setv b 10) => (setv (, a b) (, b a)) => a 10 => b 5
And now into AI routines and destructuring. I’m using A* routines by Pauli Rikula without any modifications. It’s easy to use and works well for my purposes. The interface is simple:
(a-star start goal a-map) -> (, path connections updated)
Client code calls a-star and supplies three parameters: start of the path, destination and map where traversing is done. Routine calculates the path and returns a tuple of three elements: path consisting of each square traversed, starting from start location and ending to the destination, and two lists of debug information.
I’m not interested on connections or updated, as they’re mainly useful for debugging purposes. I could call it like this:
(setv res (a-star (. character location) destination (. character level)) path (first res) ...)
but since Hy supports destructuring just like Python, I can break result into parts and store them in individual variables like this:
(setv (, path connections updated) (a-star (. character location) destination (. character level) ...)
After this I can refer to path, connections or updated within the let form.
Same structure works in many places, as shown by this list comprehension example:
=> (setv data [[1 2] [3 4] [5 6] [7 8]]) [[1, 2], [3, 4], [5, 6], [7, 8]] => (list-comp (* a b) [(, a b) data]) [2, 12, 30, 56]
Function parameters can contain lists of parameters. Every list is a parameter that get destructured when called. Lets pretend that we have decided to model complex numbers with tuples, for example 2+1i would be (, 2 1). We would like to add two complex numbers together and write following code:
=> (defn add [a b] ... (, (+ (first a) (first b)) (+ (second a) (second b)))) => (add (, 1 2) (, 3 4)) (4, 6)
However, this can be simplied:
=> (defn add [[a b] [c d]] ... (, (+ a c) (+ b d))) => (add (, 1 2) (, 3 4)) (4, 6)
results are identical.