You mentioned that local changed values cannot be captured by closure, so you need to use ref . The reason for this is that mutable values fixed in the closure must be allocated on the heap (since the closure is allocated on the heap).
F # forces you to write this explicitly (using ref ). In C #, you can “capture a mutable variable”, but the compiler translates it into a field in the heaped object behind the scene, so it will still be on the heap.
Summary: If you want to use closure, variable variables must be allocated on the heap.
Now, regarding your code - your implementation uses ref , which creates a small object for each mutable variable that you use. An alternative would be to create a single object with several mutable fields. Using the entries, you can write:
type ReadClosure = { mutable c : char mutable k : SomeType } // whatever type you use here let rec read file includepath = let state = { c = ' '; k = NONE } // ... let readc() = state.c <- stream.Read() |> char // etc...
This may be a little more efficient because you select one object instead of several objects, but I do not expect the difference to be noticeable.
There is also one confusion in your code - the stream value will be chosen after the read function returns, so the call to stream.Read may not be valid (if you call readc after read completes).
let rec read file includepath = let c = ref ' ' use stream = File.OpenText file let readc() = c := stream.Read() |> char readc let f = read a1 a2 f()
I'm not quite sure how you actually use readc , but this can be a problem for thought. Also, if you only declare this as closing the helper, you could probably rewrite the code without closing (or write it explicitly using tail-recursion, which translates into an imperative loop with mutable variables) to avoid any allocations.
Tomas Petricek May 31 '10 at 12:09 a.m. 2010-05-31 12:09
source share