(un)zurry

⇐ Notes archive

(This is an entry in my technical notebook. There will likely be typos, mistakes, or wider logical leaps — the intent here is to “let others look over my shoulder while I figure things out.”)

(un)zurry moves arguments in and out of Void-accepting closures in the same way (un)curry moves arguments in and out of tuples. Concretely, here’s how they’re defined:

The former is often helpful when staying point-free with functions that are close, but not quite the right shape you need. e.g. mapping unapplied method references:

Eep.

Let’s try to make this work.

We’d like [Int].sorted to have the form [Int] -> [Int], and since SE-0042 got rejected, we have to chisel it down on our own.

First, let’s flip the first two arguments and then address the rogue ().

Getting closer—this is where zurry can zero out the initial Void for us.

zurry(flip([Int].sorted)) // (Array<Int>) -> Array<Int>

Wicked, now we can return to our original example:

[[2, 1], [3, 1], [4, 1]].map(zurry(flip([Int].sorted))) // [[1, 2], [1, 3], [1, 4]].

Dually, unzurry shines when you’re working against a () -> Return interface, that isn’t @autoclosure’d, and you only have a Return in hand. Instead of opening a closure, you can pass along unzurry(yourReturnInstance) and call it a day.

The Point-Free folks link to Eitan Chatav’s post where he introduced the term and shows how function application is a zurried form of function composition (!).