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 xOne 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 -> eWe know that flip f swaps the first two arguments:
flip f
:: b -> a -> c -> dTwo flips in a row does nothing.
flip (flip f)
:: a -> b -> c -> dThat do-nothing example can also be written as a chain of function composition:
flip . flip . f
:: a -> b -> c -> dIf 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 -> dHowever, 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 -> eHere’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 -> dWe 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 = someDefaultArgumentSay 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 -> zWe can swap arbitrary pairs of arguments. Here’s how to flip
x and y in alphabet:
((((((((((((((((((((((flip .) .) .) .) .) .) .) .) .)
.) .) .) .) .) .) .) .) .) .) .) .) .) . alphabetOf 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.).).).).).).).).).).).).).).).).).)
alphabetThis 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