ML currying and anonymous functions

184 views Asked by At

Could someone please explain to me what is going on in these three bindings? What is the significance of the parens? What is the meaning of g and why does it have to be a g as an argument in the anonymous function? And overall what is actually happening in all of this... Thank you!

val a = fn g => (fn x => fn y => x) (g 0) (g 7);
val b = fn g => (fn x => fn y => x) (g 0) (g "happy");
val c = fn g => (fn x => fn y => x) (g 0) (g (g 7));
1

There are 1 answers

0
Aadit M Shah On BEST ANSWER

The function (fn x => fn y => x) is the constant function. It takes two arguments (x and y) and always returns the first argument (i.e. x).

This function is applied to two arguments in all three functions a, b and c:

  1. In a the constant function is applied to (g 0) and (g 7).
  2. In b the constant function is applied to (g 0) and (g "happy").
  3. In c the constant function is applied to (g 0) and (g (g 7)).

In all three cases, the result is (g 0) because the second argument is discarded. Therefore, all the three functions can be simplified to:

val a = fn g => g 0
val b = fn g => g 0
val c = fn g => g 0

Actually, the second function (i.e. b) raises a type error because g is first applied to an int and later applied to a string.

Although the functions a and c have the same result yet they do not have the same type:

  1. The type of a is (int -> 'a) -> 'a because we don't know the return type of the function g. Hence, it is a polymorphic function and it's more general than c.
  2. The type of c is (int -> int) -> int because g is applied to its own result (i.e. g is applied to (g 7)). Hence, its return type must be the same as its argument type (i.e. int).

Therefore, a is more general than c and every instance of c can be safely replaced with a but not vice versa.