2
$\begingroup$

The following is the code to curry or uncurry a function in Haskell:

curry :: ((a, b) -> c) -> a -> b -> c
curry f a b = f (a, b)

uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f (a, b) = f a b

I can understand the type signature part but not the function definition. Would you please explain me how those function bodies turn a curried function into an uncurried one and vice versa?

$\endgroup$
3
$\begingroup$

The meaning of curry can be easier to be seen when the type signature is written as

curry :: ((a, b) -> c) -> (a -> b -> c)

that is, a function taking a single parameter of type (a, b) and yielding a result of type c is turned into a function taking two separate values of types a and b yielding the same result type c.

We might define curry for this signature like this:

curry f = g

where f :: ((a, b) -> c) and g :: (a -> b -> c).

f is passed by the user, but how do we get g? We know g is a function taking two parameters and yielding a result type, so it must structurally look like \x -> \y -> z, where x :: a, y :: b, and z :: c (\v -> e is the syntax for lambda-expressions in Haskell). We now have to find a way to get the result z from x and y such that the types work out correctly.

As both result types c must be the same, the only way to get z is to use f and apply it to a value of type (a, b). So we know z = f (?, ?) where (?, ?) must have type (a, b). Where do we get values of these types from? Again, as the types must match exactly, the only option is to use x and y here. We get

curry f = g
    where g = \x -> \y -> f (x, y)

This would be a proper implementation for curry. One that is easier to read is to inline g:

curry f = \x -> \y -> f (x, y)

As Haskell allows us to define functions with multiple parameters, we can resolve the lambda-expression and simplify this to

curry f x y = f (x, y)

which is (beside different variable names) the same implementation as in your question.

For uncurry the procedure is similar (note that you had missing parentheses in the type signature for uncurry in your original question which lead to a different type).

From

uncurry :: (a -> b -> c) -> ((a, b) -> c)

we conclude

uncurry f = g
    where g = \(x, y) -> z

with f :: (a -> b -> c), g :: (a, b) -> c, x :: a, y :: b and z :: c. Following the types, z can only be defined by z = f x y. From that we get

uncurry f = g
    where g = \(x, y) -> f x y

and after inlining g and removing the lambda

uncurry f (x, y) = f x y
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.