thread macro

Let’s talk about clojure for a bit. Or lisps in general, I guess. A lot of the “kinda joking except not really” quips that commonly float around on the internet are about the parentheses, as in how there are so many of them. For example, if you want to take a number x and add one, multiply by two, then add 3, the code might naively look something like this:

(+ (* (+ x 1) 2) 3)

Or perhaps like this:

(+ 3 (* 2 (+ 1 x)))

Look at the parens! Especially the consecutive 3 closing ones in the second variation. For a sufficiently long chain of functions, it can get pretty unreadable—especially with multiple arguments and whatnot.

Enter clojure’s thread macro. The thread macro is a macro in the form of (-> x & forms), and it “threads” x through the forms as the first arg*. Which sounds terribly confusing explained, so an example is probably better here. Take this snippet using the thread macro:

;; add one, multiply by two, and add three
(-> x
  (+ 1)
  (* 2)
  (+ 3))

This desugars into (+ (* (+ x 1) 2) 3), i.e. the first variation of the initial example above. Personally, I find the macro version much more readable since each call is on its own line, and it seems more expressive of applying a series of functions to the initial x.

The thread macro is also useful for chaining together collection methods like map. Since clojure doesn’t have first-class OO support (instead favoring protocols and such), map exists as a regular function that takes the collection as an arg, instead of as a method on a collection class. So chaining together a bunch of ops on a vector might look something like…

;; add one to every number and filter for even numbers
(->> [1 2 3 4 5 6]
  (map #(+ 1 %))
  (filter even?))

;; Without the thread macro, would look like:
(filter even? (map #(+ 1 %) [1 2 3 4 5 6]))

The only difference is that in this case, ->> was used. ->> is “thread last”, which is like -> (“thread first”), except it inserts the expression at the end of the form.

This pattern also exists in other languages (especially those that don’t offer first-class OO, which allows fancy return self type stuff), like Elixir’s pipe |> (in the spirit of the unix pipe) which is what prompted me to spread the word about this:

# double and add one to each element
[1, 2, 3]
|> Enum.map(fn x -> x * 2)
|> Enum.map(fn x -> x + 1)

The thread macro pattern doesn’t have as much of a place in Scala, since Scala has mechanisms like the collection library and implicit conversions to help express similar logic in elegant ways. But when I first read up on macros in lisp, I spent some time scratching my head at the day-to-day practical uses until I found this and had my first “ohhhhhhhhhhhh” moment. In any case, hope this was mildly interesting!

* - Well technically, as the second item in the form, which is effectively the first arg for functions… But that might be a bit too lispy.

Bonus

When I published this email to the internal list, it generated some discussion wherein I learned that there are other neat features of the same sort like doto, and that they’re all just various derivations of the K combinator. Of course, googling k-combinators led to a pretty heavy looking wiki page, so I was referred to http://combinators.info/ , which I have been trying to get through since.

vim % expansion

% (Current File Name)

Another vim tip this week! This time, it’s about ‘%’, which expands to ‘current file name’. This is especially useful in projects with java/scala style directory setups, where your source is approximately 1.5 million folders away from the project root, but you kind of want to hang around project root for things like ant/sbt/etc to work. % makes this easier to work with files in the deeply nested folders while doing this.

Taking a contrived example, instead of doing something like this to git log the file you are currently editing:

:!git log src/main/scala/com/bizo/(…)/Foo.scala

You can just do:

:!git log %

This is extremely convenient and works everywhere in command line mode (basically, whenever ‘:’ is used), but is also useful to have if you’re ever writing vim script. See :h expand for the function to use in vim script, and some other special keywords.

But wait! There’s more!

Vim also supports file modifiers. For example, :h gives you the ‘head’ of the file name, i.e. the directory of the file. Taking another (contrived) example, you can git add the entire folder containing the file you are editing by doing something like:

:!git add %:h

See :h file-modifiers for more details (and more modifiers).

Another Convenient Expansion

I use %:h so often (for example, when I realize I’ve opened a file before creating the directory containing it, or am editing a file in a directory that doesn’t exist) that I’ve made a shortcut for it in my vimrc:

cnoremap %% <C-R>=expand('%:h').'/'<CR>

Roughly speaking, it remaps the key chord %% in command line mode to paste from a special register that evals the vim script inside it, which calls the expand() function.

Long story short, what this allows me to do is do something like:

:!mkdir -p %%

And the %% will expand in-place into whatever %:h resolved to. Not only is this a win because it’s slightly less to type than %:h, but the expansion also allows you to quickly modify your command on the fly and go up/down a directory if needed.

And of course, here’s the requisite asciinema with a quick demo of this in action:

Hope that’s useful / mildly interesting!