First of all, your expandPair
function is literally the same definition as uncurry
, which is in Prelude
.
The problem here is that fboth snd
takes 2 arguments, so the normal composition operator is not quite suited for this task. However, you can make a rather strange looking operator that lets you "compose" a function that takes two arguments with a function that takes 1 argument:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
The easy mnemonic for remembering this is that the function on the side with one dot takes 1 argument, of the same type as the output of the function that takes two arguments, which is on the side with two dots. You can then write this as
sortBy (uncurry compare .: fboth snd) [(1, 2), (3, 4)]
Now, I will say that it's best not to really think about how the .:
operator works, just look at its type rather than its definition. It does come in handy fairly often, I use it pretty regularly and I certainly didn't come up with this operator.
You can also implement it as
> :m +Data.Function
> sortBy (compare `on` snd) ...
-- sortBy (on compare snd) ...
But as @mhwombat has pointed out, Data.Ord
has an alias for on compare
called comparing
:
> :m +Data.Ord
> sortBy (comparing snd) ...
which is my preference.
Something that might make this operator a little more clear:
> :t (id .: (,))
a -> b -> (a, b)
> (id .: (,)) 1 2
(1, 2)
> (fst .: (,)) 1 2
1
> (snd .: (,)) 1 2
2
> (negate .: (+)) 1 2
-3