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:
-> b -> c) -> (b -> a -> c) (a
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
= flip . flip (flip . flip f) $ c
thirdArgApplied where c = someDefaultArgument
Say we had a massive 25-argument function:
alphabet :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j ->
-> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v ->
k -> x -> y -> z w
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 ->
-> u -> i -> c -> k ->
q -> r -> a -> w -> n -> y ->
b -> o -> x ->
f -> g -> j -> l -> m -> p -> s -> v -> z d