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?
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