Kostas
Kostas

Reputation: 4186

"Curry" from tuple in SML

I am trying to define a function wrapper that curries a tuple in SML.

fun curry f = fn (x, y) z => f x y z;

Gives me the error

Non-identifier applied to a pattern.

I am new to ML and not sure why the pattern matching in fn doesn't work.

How could I make this work?

Upvotes: 2

Views: 733

Answers (1)

sshine
sshine

Reputation: 16135

I am trying to define a function wrapper that curries a tuple in SML.

fun curry f = fn (x, y) z => f x y z;

How could I make this work?

Closures in SML don't allow for multiple arguments, but you can nest them instead.

What curry usually does is take a function f that normally accepts a tuple (x, y) and instead returns a modified function that takes x and y separately. Here is a number of equivalent ways to define curry:

fun curry f x y = f (x, y)
fun curry f x = fn y => f (x, y)
fun curry f = fn x => fn y => f (x, y)
val curry = fn f => fn x => fn y => f (x, y)

Its opposite, uncurry instead takes a function f that takes x and y separately and returns a modified function that takes (x, y). Here is one way to write uncurry:

fun uncurry f (x, y) = f x y

It's easy to mix up the two.

One way to fix the function you've written so that it compiles is insert an extra => fn:

fun what_is_this f = fn (x, y) => fn z => f x y z
                            (* ^- there *)

Before giving it a name, let's analyse what it does. It has the type signature:

fn : ('a -> 'b -> 'c -> 'd) -> 'a * 'b -> 'c -> 'd
                  (* now a tuple -^    ^- still curried *)

meaning that it takes a function of three curried arguments (x, y and z) and returns a modified function where the first two arguments are now in a tuple (uncurried) and the third is still curried. This is really a less generic version of uncurry. A more clear way of writing it would be:

fun what_is_this f (x, y) z = f x y z

If you use uncurry on a function of three arguments, you get the same effect, but you can't use what_is_this on anything with two curried arguments. So I'd say that this is a less useful variant of uncurry.

There are however other more useful variants of curry/uncurry. For example, you could make an uncurry_twice that converts f x y z into (uncurry_twice f) ((x, y), z), or an uncurry3 that converts f x y z into (uncurry3 f) (x, y, z):

fun uncurry_twice f = uncurry (uncurry f)
fun uncurry3 f (x, y, z) = f x y z

Upvotes: 6

Related Questions