【问题标题】:Why aren't F# records allowed to have AllowNullLiteralAttribute?为什么不允许 F# 记录具有 AllowNullLiteralAttribute?
【发布时间】:2009-12-06 19:34:01
【问题描述】:

记录不能具有 AllowNullLiteralAttribute 属性是否存在编译器实现原因,或者这是一个选择的约束?

我确实看到这种约束有时会强制代码更清晰,但并非总是如此。

[<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

// Would 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

为对可变性不满意的人群添加了不可变版本。在这种情况下,它大约快 30%。

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)

【问题讨论】:

  • 顺便说一句,您需要可变树有什么特别的原因吗?我个人认为不可变的更简洁,更易于使用,并且在函数式语言中更惯用。
  • 没有可变树的实现会变得非常复杂。上面是一个简单的案例,但是当您尝试实现插入和删除时,类似非重叠范围树的东西会变得混乱。如何处理删除级联节点或插入一个节点合并到多个其他节点的情况。这种树结构本质上是可变的。
  • "删除级联节点或者插入一个节点合并到多个其他节点的情况如何处理。" -- 只是为了好玩(也可能是为了卖淫!),你问另一个问题,关于如何将你的可变树转换成不可变树。
  • 好的,给我几分钟,我会发布它。

标签: f# attributes nullable record


【解决方案1】:

我只能冒险猜测,但该语言似乎采取了避免使用 null 的立场(如果需要该功能,您始终可以使用 option 类型),因此使用null 确实应该被限制为与其他.NET 语言的互操作。因此,F# 特定类型不允许使用null

【讨论】:

  • 约束绝对不在CLR级别:AllowNullLiteral适用于类,记录类型是(密封的)类。我希望它可能源自 OCAML(出于上述原因)。
【解决方案2】:

嗯,记录像其他构造一样被转换为标准 .NET 类,所以我看不出技术原因。

我想这个决定是相当哲学的 - Null 值是未初始化的、未定义的值,在有状态计算中会被替换。在 F# 等函数式上下文中应避免这些。

所以我认为记录类型作为“功能构造”(不是标准的 .NET 兼容)并不意味着携带此类非功能数据,但用户需要手动对其进行编码(`选项类型等)。

这也让你可以推理你的代码,例如检查所有可能值的模式匹配,而不必处理 null 值的潜在危险。

至于你的代码:你真的要求它是必要的吗?怎么样

data Tree = 
    | Node of int * Tree * Tree
    | Nil

【讨论】:

  • 顺便说一句,Tony Hoare 今年夏天举办了一场关于 null ref 的演讲:infoq.com/presentations/…
  • 以上只是一个人为的例子。我主要关心的是互操作。几乎我参与过的每个主要项目都有大量的互操作性。
猜你喜欢
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2015-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
相关资源
最近更新 更多