1. 18
1.

2. 6

This works because `(apply zip lis)` is like a matrix transpose, so it undoes itself. For example, if `lis` is `'((1 2 3) (a b c))` then you get `(zip '(1 2 3) '(a b c))`, which is `'((1 a) (2 b) (3 c))`.

It’s surprising because normally I think of `zip` as converting (list, list) to list-of-tuples. But in Scheme, the cons/nil structures are playing both roles: tuples and lists.

1. 3

Here is a matrix representation of the data:

``````1 2 3
a b c
``````

Yeah, I see what you mean. Thank you. Given that that’s what it is, the names zip and unzip becomes kinda unhelpful. It’s also annoying that one works on a list and returns vals, and the other works on args and returns a list. Some monomorphism there would’ve been nice. So `compose zip zip` would’ve become equal?-identity.

2. 3

Is there a blog post/manual/book I can reference to get myself the background required for this, because it seems very cool, but I have no idea what’s going on?

1. 1

This is my understanding.

Imagine a function `zip` which takes a tuple of lists and returns a list of tuples, for example:

``````zip
([1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e']) =
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
``````

`unzip` just does the opposite:

``````unzip
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')] =
([1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e'])
``````

Now, imagine `zip` takes a list of lists instead:

``````zip
[[1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e']] =
[[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]
``````

You can represent the argument list of lists as a 5x2 matrix, like so:

``````1 2 3 4 5
a b c d e
``````

and the returned list of lists as a 2x5 matrix, like so:

``````1 a
2 b
3 c
4 d
5 e
``````

(I’ll treat matrix and list of lists as interchangeable in meaning.)

That makes it clear that a `zip` which takes an arbitrary length list of lists instead of a fixed-size tuple (or triple, &c) of lists can simply be considered equivalent to `transpose`. `transpose` applied to a matrix returns a new matrix which returns the original matrix when applied to `transpose` again; i.e.

``````(transpose . transpose) matrix = matrix
``````

Or, for an example:

``````transpose
[[1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e']] =
[[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]

# and

transpose
[[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']] =
[[1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e']]
``````

So, when you think about it, you realise that `unzip` is simply `zip`, because `zip` is simply `transpose` and `transpose` applied to a once-transposed matrix simply returns the original matrix, i.e. `transpose` is equivalent to `untranspose` (which doesn’t exist named as such because it’s just `transpose`).

Unfortunately, while this is the case mathematically, `unzip` is still needed because in practice, (AFAIK) most (statically typed?) programming language’s `zip` implementations (at least in stdlib) act on tuples of lists and return lists of tuples instead of heterogenous lists of lists.