So now to test if you have understood, consider this
piece of code:

fun f (var x:int) (y:int) => x + y;

var a : (int -> int)^5;
for var i in 0 upto 4 do
  a.i = f i;
done
var y = 100;
for i in 0 upto 4 do  
  println$ a.i y;
done

Here we make an array of closures, then apply each later
to the value. note x is a var, so eager evaluation.

~/felix>build/release/host/bin/flx --test=build/release ac
104
104
104
104
104

What, I though  you said eager evaluation!
That's using the last value of i! That's not
eager evaluation!

Yes, it is. Let me prove it:

fun f (var x:int) (y:int) => x + y;

var a : (int -> int)^5;
for var i in 0 upto 4 do
  var k = i;
  a.i = f k;
  ++k;
done
var y = 100;
for i in 0 upto 4 do  
  println$ a.i y;
done

~/felix>build/release/host/bin/flx --test=build/release ac
104
104
104
104
104

See? k got incremented, but we didn't get a row of 105's did we??
Lets try this (note the x parameter):

fun f (x:int) (y:int) => x + y;

var a : (int -> int)^5;
for var i in 0 upto 4 do
  var k = i;
  a.i = f k;
  ++k;
done
var y = 100;
for i in 0 upto 4 do  
  println$ a.i y;
done

~/felix>build/release/host/bin/flx --test=build/release ac
105
105
105
105
105

See? Now we have lazy evaluation. It's clear what is happening:
the application f k is inlined, and in the first (var) case it says:

        var x = k;
        a .i = fun (y:int) => x + y;

and in the val case it is saying

        a.i = fun (y:int) => k + y;

which is lazy. So finally lets look at this:

noinline fun f (x:int) (y:int) => x + y;

var a : (int -> int)^5;
for var i in 0 upto 4 do
  var k = i;
  a.i = f k;
  ++k;
done
var y = 100;
for i in 0 upto 4 do  
  println$ a.i y;
done
 
~/felix>build/release/host/bin/flx --test=build/release ac
100
101
102
103
104

Even though x is a val here, f is a closure because it's marked noinline.

The problem here is quite clear, without the noinline, f is inlined, and even 
though
it uses eager evaluation, it evaluates the parameter to i. But then the closure
which is ACTUALLY created is referring to the x inlined into the loop.

There's only one x in the loop. It holds the value before the closure was
created but it isn't an argument to the closure, and the next iteration,
x gets a new value. Since all the actual closure just say:

        fun closure (y:int) => x + y;

they all use the same value of x, since the x they're using is the
one when the closure is called, which has value 4.

The issue here is quite clear: there are 5 closures with 5 copies
of y but there's only one copy of x because of the inlining.

The "var" is clearly causing eager evaluation. But it doesn't change
the fact the closure produced is bound to a single x variable in its
context. The x is NOT an argument of the closure.

To force a unique copy of x, we make f noinline so even the application

        f k

is the application of a closure f.

I really don't like this, but I don't see an alternative.
A variable is intrinsically a constant machine address of a storage slot.
When you use its name in a r-context you get the current value of the variable
store in the slot. The only way to get distinct values is create distinct slots.


--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce.
With Perforce, you get hassle-free workflows. Merge that actually works. 
Faster operations. Version large binaries.  Built-in WAN optimization and the
freedom to use Git, Perforce or both. Make the move to Perforce.
http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to