mitchell vitez blog music art media dark mode

Flippant Haskell

Given a Haskell function func :: a -> b -> c, we can produce a function flippedFunc :: b -> a -> c easily using flip from Prelude.

flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x

One of my favorite ways to explain flip uses the fact that because the function arrow (->) associates to the right, we can rewrite the type signature as:

(a -> b -> c) -> (b -> a -> c)

This indicates a transformation from one function into another function, with the order of the first two arguments reversed.

However, what if we want an arbitrary reordering of function arguments? There’s actually a straightforward (if messy) recipe to produce reorderings using just flip and composition (.), but it requires understanding a few rules.

First, flip by itself only swaps the first two arguments. Doing two flips in a row flip (flip f) is idempotent, meaning a double flip has no effect on f’s behavior.

For the following examples, let’s use this three-argument function f and four-argument function g:

f :: a -> b -> c -> d
g :: a -> b -> c -> d -> e

We know that flip f swaps the first two arguments:

flip f
  :: b -> a -> c -> d

Two flips in a row does nothing.

flip (flip f)
  :: a -> b -> c -> d

That do-nothing example can also be written as a chain of function composition:

flip . flip . f
  :: a -> b -> c -> d

If we want to swap arguments other than the first two, we need to compose. For example, to swap the second and third argument, we use flip . f

flip . f
  :: a -> c -> b -> d

However, we’ve already seen that flip . flip . f takes us back to doing nothing. If we wanted to swap the third and fourth arguments of some four-argument function g, we’d need to nest compositions.

(flip .) . g
  :: a -> b -> d -> c -> e

Here’s a listing of how we can generate all the possible argument order permutations of f:

f
  :: a -> b -> c -> d

flip . f
  :: a -> c -> b -> d

flip f
  :: b -> a -> c -> d

flip . flip f
  :: b -> c -> a -> d

flip . flip (flip . flip f)
  :: c -> a -> b -> d

flip (flip . flip f)
  :: c -> b -> a -> d

We can use these flipped functions to do certain things, like partial application of arbitrary arguments.

thirdArgApplied :: a -> b -> d
thirdArgApplied = flip . flip (flip . flip f) $ c
  where c = someDefaultArgument

Say we had a massive 25-argument function:

alphabet :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j ->
  k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v ->
  w -> x -> y -> z

We can swap arbitrary pairs of arguments. Here’s how to flip x and y in alphabet:

((((((((((((((((((((((flip .) .) .) .) .) .) .) .) .)
  .) .) .) .) .) .) .) .) .) .) .) .) .) . alphabet

Of course, what this all means is that we can do arbitrary manipulations of argument orderings, no matter how convoluted. Here’s an example where I’ve additionally used $ (instead of just parentheses, flip, and .) for…um…readability:

((((((((((((((((flip.).).).).).).).).).).).).).).).)$(((((((
((((((((((flip.).).).).).).).).).).).).).).).).)$(((((((((((
(((((((flip.).).).).).).).).).).).).).).).).).)$((((((((((((
(((((((flip.).).).).).).).).).).).).).).).).).).)$((((((((((
((((((((((flip.).).).).).).).).).).).).).).).).).).).)$(((((
((((((((((((((((flip.).).).).).).).).).).).).).).).).).).).)
.)$((((((((((((((((((((((flip.).).).).).).).).).).).).).).).
).).).).).).)$(((((((((((((((((((((((flip.).).).).).).).).).
).).).).).).).).).).).).).)$(((((((((((((((flip.).).).).).).
).).).).).).).).)$((((((((((((((((flip.).).).).).).).).).).)
.).).).).)$(((((((((((((((((flip.).).).).).).).).).).).).).)
.).).)$((((((((((((((((((flip.).).).).).).).).).).).).).).).
).).)$(((((((((((((((((((flip.).).).).).).).).).).).).).).).
).).).)$((((((((((((((flip.).).).).).).).).).).).).).)$(((((
((((((((flip.).).).).).).).).).).).).)$((((((((((((((flip.).
).).).).).).).).).).).).)$(((((((((((((((flip.).).).).).).).
).).).).).).).)$((((((((((((((((flip.).).).).).).).).).).).)
.).).).)$(((((((((((((((((flip.).).).).).).).).).).).).).).)
.).)$((((((((((((((((((flip.).).).).).).).).).).).).).).).).
).)$(((((((((((((((((((flip.).).).).).).).).).).).).).).).).
).).)$((((((((((((((((((((flip.).).).).).).).).).).).).).).)
.).).).).)$(((((((((((((((((((((flip.).).).).).).).).).).).)
.).).).).).).).).)$((((((((((((((((((((((flip.).).).).).).).
).).).).).).).).).).).).).).)$(((((((((((((((((((((((flip.).
).).).).).).).).).).).).).).).).).).).).).)$((((((((((((flip
.).).).).).).).).).).).)$(((((((((((((flip.).).).).).).).).)
.).).).)$((((((((((((((flip.).).).).).).).).).).).).).)$((((
(((((((((((flip.).).).).).).).).).).).).).).)$((((((((((((((
((flip.).).).).).).).).).).).).).).).)$(((((((((((((((((flip
.).).).).).).).).).).).).).).).).)$(((((((((((flip.).).).).)
.).).).).).)$((((((((((((flip.).).).).).).).).).).).)$((((((
(((((((flip.).).).).).).).).).).).).)$((((((((((((((flip.).)
.).).).).).).).).).).).)$(((((((((((((((flip.).).).).).).).)
.).).).).).).)$((((((((((((((((flip.).).).).).).).).).).).).
).).).)$(((((((((((((((((flip.).).).).).).).).).).).).).).).
).)$((((((((((((((((((flip.).).).).).).).).).).).).).).).).)
.)$(((((((((((((((((((flip.).).).).).).).).).).).).).).).).)
.).)$((((((((((((((((((((flip.).).).).).).).).).).).).).).).
).).).).)$(((((((((((((((((((((flip.).).).).).).).).).).).).
).).).).).).).).)$(((((((((flip.).).).).).).).).)$((((((((((
flip.).).).).).).).).).)$(((((((((((flip.).).).).).).).).).)
.)$((((((((((((flip.).).).).).).).).).).).)$(((((((((((((
flip.).).).).).).).).).).).).)$((((((((((((((flip.).).).).)
.).).).).).).).).)$(((((((((((((((flip.).).).).).).).).).).)
.).).).)$((((((((((((((((flip.).).).).).).).).).).).).).).).
)$(((((((((((((((((flip.).).).).).).).).).).).).).).).).)$((
((((((((((((((((flip.).).).).).).).).).).).).).).).).).)$(((
(((((flip.).).).).).).).)$(((((((flip.).).).).).).)$((((((((
flip.).).).).).).).)$(((((((((flip.).).).).).).).).)$(((((((
(((flip.).).).).).).).).).)$(((((((((((flip.).).).).).).).).
).).)$((((((((((((flip.).).).).).).).).).).).)$((((((flip.).
).).).).)$(((((((flip.).).).).).).)$(((((flip.).).).).)$((((
((flip.).).).).).)$(((((((flip.).).).).).).)$((((((((flip.).
).).).).).).)$(((((((((flip.).).).).).).).).)$((((((((((flip
.).).).).).).).).).)$((((flip.).).).)$(((((flip.).).).).)$((
((((flip.).).).).).)$(((((((flip.).).).).).).)$((((((((flip.
).).).).).).).)$(((((((((flip.).).).).).).).).)$((((((((((
flip.).).).).).).).).).)$(((((((((((flip.).).).).).).).).).)
.)$((((((((((((flip.).).).).).).).).).).).)$(((((((((((((
flip.).).).).).).).).).).).).)$((((((((((((((flip.).).).).).
).).).).).).).).)$(((((((((((((((flip.).).).).).).).).).).).
).).).)$((((((((((((((((flip.).).).).).).).).).).).).).).).)
$(((((((((((((((((flip.).).).).).).).).).).).).).).).).)$(((
(((((((((((((((flip.).).).).).).).).).).).).).).).).).)$((((
(((((((((((((((flip.).).).).).).).).).).).).).).).).).).)$((
(flip.).).)$((((flip.).).).)$(((((flip.).).).).)$((((((flip.
).).).).).)$(((((((flip.).).).).).).)$((((((((flip.).).).).)
.).).)$(((((((((flip.).).).).).).).).)$((((((((((flip.).).).
).).).).).).)$(((((((((((flip.).).).).).).).).).).)$((((((((
((((flip.).).).).).).).).).).).)$(((((((((((((flip.).).).).)
.).).).).).).).)$((((((((((((((flip.).).).).).).).).).).).).
).)$(((((((((((((((flip.).).).).).).).).).).).).).).)$((((((
((((((((((flip.).).).).).).).).).).).).).).).)$((flip.).)$((
(flip.).).)$((((flip.).).).)$(((((flip.).).).).)$(flip.)$((
flip.).)$(((flip.).).)$((((flip.).).).)$(((((flip.).).).).)$
((((((flip.).).).).).)$(((((((flip.).).).).).).)$flip$(flip.
)$((flip.).)$(((flip.).).)$((((flip.).).).)$(((((flip.).).).
).)$((((((flip.).).).).).)$(((((((flip.).).).).).).)$(((((((
(flip.).).).).).).).)$(((((((((flip.).).).).).).).).)$((((((
((((flip.).).).).).).).).).)$(((((((((((flip.).).).).).).).)
.).).)$((((((((((((flip.).).).).).).).).).).).)$((((((((((((
(flip.).).).).).).).).).).).).)$((((((((((((((flip.).).).).)
.).).).).).).).).)$(((((((((((((((flip.).).).).).).).).).).)
.).).).)$((((((((((((((((flip.).).).).).).).).).).).).).).).
)$(((((((((((((((((flip.).).).).).).).).).).).).).).).).)$((
((((((((((((((((flip.).).).).).).).).).).).).).).).).).)
alphabet

This is a (thoroughly) flipped-around version of alphabet, with the type signature:

:: t -> h -> e ->
   q -> u -> i -> c -> k ->
   b -> r -> a -> w -> n -> y ->
   f -> o -> x ->
   d -> g -> j -> l -> m -> p -> s -> v -> z