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
[email protected]
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/felix-language