Почему записи F # не могут иметь атрибут AllowNullLiteralAttribute? - PullRequest
3 голосов
/ 06 декабря 2009

Существует ли причина реализации компилятора, почему записи не могут иметь атрибут 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)

Ответы [ 2 ]

3 голосов
/ 06 декабря 2009

Я могу рискнуть только предположением, но язык, похоже, придерживается позиции, что использование null - это то, чего следует избегать (вы всегда можете использовать тип option, если вам нужна эта функциональность), и поэтому использование null действительно должно ограничиваться взаимодействием с другими языками .NET. Следовательно, типы F # не позволяют использовать null.

2 голосов
/ 06 декабря 2009

Хм, записи переводятся в стандартные .NET-классы, как и другие конструкции, поэтому я не вижу технической причины.

Я думаю, что решение довольно философское - Null значения являются неинициализированными, неопределенными значениями, то, что заменяется в вычислениях с состоянием. Этого следует избегать в функциональном контексте, например, F #.

Поэтому я думаю, что типы записей как «функциональная конструкция» (не совместимые со стандартом .NET) не предназначены для переноса таких нефункциональных данных, но пользователь обязан кодировать их вручную («типы опций и т. Д.»).

Это также позволяет вам рассуждать о вашем коде и, например, проверить соответствие шаблона для всех возможных значений без потенциальной опасности иметь дело с null значениями.

Что касается вашего кода: вам действительно нужно, чтобы он был таким императивом? Как насчет

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