Composing functions with multiple values
I see a certain imbalance between multiple function arguments and multiple function values. On the one hand functions with multiple arguments are often in curried form, like
(++) :: [a] -> [a] -> [a]
which allows for partial application. On the other hand, functions cannot emit values in a compatible way, and thus must return pairs instead. Example:
partition :: (a -> Bool) -> [a] -> ([a], [a])
You can't convert a pair to something that fits a function that accepts two arguments in curried form. But you can convert the curried functionto one that accepts pairs using the standard function
uncurry (++) :: ([a], [a]) -> [a]
uncurry (++) . partition p :: [a] -> [a]
is what you are after.
In fact, there is no imbalance. Functions always accept exactly one input and emit exactly one output. You can always choose tuples as both input and output. Using tuples as input is close to the way other languages handle multiple inputs. If you choose the curried form you do that because of partial application. In this case you should also think intensively about how to order the parameters in order to make partial application useful.