The uncurry function only works for functions taking two arguments:
uncurry :: (a -> b -> c) -> (a, b) -> c
If I want to uncurry functions with an arbitrary number of arguments, I could just write separate functions:
uncurry2 f (a, b) = f a b
uncurry3 f (a, b, c) = f a b c
uncurry4 f (a, b, c, d) = f a b c d
uncurry5 f (a, b, c, d, e) = f a b c d e
But this gets tedious quickly. Is there any way to generalize this, so I only have to write one function?
Try
uncurryNfrom the tuple package. Like all forms of overloading, it’s implemented using type classes. In this case by manually spelling out the instances up to 15-tuples, which should be more than enough.Variadic functions are also possible using type classes. One example of this is Text.Printf. In this case, it’s done by structural induction on the function type. Simplified, it works like this:
It shouldn’t be hard to see that
foocan be instantiated to the typesIO a,a -> IO b,a -> b -> IO cand so on. QuickCheck also uses this technique.Structural induction won’t work on tuples, though, as an n-tuple is completely unrelated to a n+1-tuple, so that’s why the instances have to be spelled out manually.