New F# developer, long time C# developer. As an exercise in learning F#, I'm working my way through Eric Lippert's series on graph coloring translating from his C# to F#. I'm currently working on part two.
The original C# is in the blog post - here's the F# translation so far - but it doesn't compile:
type BitSet = struct
val bits : int
private new(b) = { bits = b }
static member Empty = BitSet(0)
member this.Contains (item:int) = (this.bits &&& (1<<< item)) <> 0
member this.Add (item:int) = BitSet(this.bits ||| (1 <<< item))
member this.Remove (item:int) = BitSet(this.bits &&& ~~~(1<<<item))
member this.Bits = seq {
for item in 0..31 do
if this.Contains(item) then
yield item
}
end
This produces the very mysterious error "error FS0406: The byref-typed variable 'this' is used in an invalid way. Byrefs cannot be captured by closures or passed to inner functions" from the definition of Bits:seq<int>.
Curiously, changing the keyword "struct" to "class" results in valid code. Coming from a C# perspective, this seems like nonsense, but I'm sure there's a valid reason behind it. The question is - how should I write the Bits function? What's the underlying F# principle that I need to understand for this to make sense?
I think the problem is that the
this
reference is created as a reference to the current value of the struct, so that you can modify the struct (if you wanted and the struct was mutable).This causes problem inside
seq { .. }
because this generates code inside another class and so the compiler fails to pass the reference to the "this" instance.If you assign the
this
value an ordinary local variable, then the code works fine:As a matter of style - I would probably use an implicit constructor, which makes the code a bit shorter. I also prefer the
Struct
attribute over the explicitstruct .. end
syntax, but both of these are just a matter of style (and I'm sure others will have different preferences). You might find it useful just as an alternative or for comparison: