Question

I have this statement:

let val x = 
    let val x = 5
    in(fn y =>(y,x+y))
    end
     in
     let val y=3 and z=10
     in x z 
     end 
     end;

The output is :

(10,15)

I've been trying to track how this answer was produced but am getting confused. Is there a better way to write this that would help me understand what variables are being used where? Thank you!

Was it helpful?

Solution

First, some alpha-conversion:

let val fnPairOfInputAndInputPlus5 = 
    let val five = 5
     in ( fn input => ( input, five + input ) )
    end
 in let val ignored = 3 and input = 10
     in fnPairOfInputAndInputPlus5 input 
    end 
end;

This code is demonstrating that when you declare a function value, unbound values in the declaring scope, such as the value five, are "enclosed" by the declaration (hence the term "closures"). Thus the function always returns a pair consisting of its input and its input plus five.

OTHER TIPS

You could simplify it to

let fun f y = (y,5+y)
    val y=3 and z=10
in
  f z
end;

Note that the two instances of y are independent. The inner occurrence of x (which I've eliminated) is independent of the outer one (now renamed f).

Can be understood using manual evaluation with detailed explanations.

Starting with your initial expression:

let val x = 
   let val x = 5
   in (fn y => (y,x + y))
   end
in
   let val y = 3 and z = 10
   in x z 
   end 
end;

Line 2,3,4 is an expression whose type is a function, as you see in the in part. It does not depends on any outer context, so it may be simplified as just fn y => (y, 5 + y), substituting x to 5, according to the binding given in let.

So you now have this:

let val x = fn y => (y, 5 + y)
in
   let val y = 3 and z = 10
   in x z 
   end 
end;

After substitution of x (and removal of the let which in then now not necessary any more):

let val y = 3 and z = 10
in (fn y => (y, 5 + y)) z 
end;

Note the y appearing in (y, 5 + y) are bound to the function's argument, and not to 3. There is no reference to this outer y, so its biding may be removed.

Now you have:

let z = 10
in (fn y => (y, 5 + y)) z 
end;

Substituting z to 10 and removing the let which is not necessary any more, you get:

(fn y => (y, 5 + y)) 10;

This is a function application. You may evaluate it, to get:

(10, 5 + 10);

Which gives the final and constant result you noticed:

(10, 15);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top