Why aren't F# records allowed to have AllowNullLiteralAttribute?
Is there a compiler implementation reason why records can't have the AllowNullLiteralAttribute attribute or is this a chosen constraint?
I do see this constraint force cleaner code sometimes but not always.
[<AllowNullLiteralAttribute>]
type IBTreeNode = {
mutable left : IBTreeNode; mutable right : IBTreeNode; mutable value : int}
with
member this.Insert x =
if x < this.value then
if this.left = null then
this.left <- {left = null; right = null; value = x}
else
this.left.Insert x
else
if this.right = null then
this.right <- {left = null; right = null; value = x}
else
this.right.Insert x
// Wo开发者_如何学编程uld be a lot of boilerplate if I wanted these public
[<AllowNullLiteralAttribute>]
type CBTreeNode(value) =
let mutable left = null
let mutable right = null
let mutable value = value
with
member this.Insert x =
if x < value then
if left = null then
left <- CBTreeNode(x)
else
left.Insert x
else
if right = null then
right <- CBTreeNode(x)
else
right.Insert x
Added an immutable version for the frown on mutability crowd. It's about 30% faster in this case.
type OBTree =
| Node of OBTree * OBTree * int
| Null
with
member this.Insert x =
match this with
| Node(left, right, value) when x <= value -> Node(left.Insert x, right, value)
| Node(left, right, value) -> Node(left, right.Insert x, value)
| Null -> Node(Null, Null, x)
I can only hazard a guess, but the language seems to take the position that the use of null
is something to be avoided (you can always use an option
type if you need that functionality), and so the use of null
is really something that ought to be limited to interop with other .NET languages. Therefore, F# specific types don't allow the use of null
.
Hmm, records are translated to standard .NET-classes like other constructs, so I don't see a technical reason.
I guess the decision is rather philosophical - Null
values are uninitialized, undefined values, something that gets replaced within stateful computations. These are to be avoided in functional context like F#.
So I think that record types, as a "functional construct" (not standard .NET-compatible) aren't meant to carry such unfunctional data but the user is required to code it manually (`option types etc.).
This also allows you to reason about your code and e.g. check a pattern matching for all possible values without the potential danger of having to deal with null
values.
As to your code: Do you really require it to be that imperative? What about
data Tree =
| Node of int * Tree * Tree
| Nil
精彩评论