Границы / Домен в единицах измерения - PullRequest
1 голос
/ 16 июля 2011

Я нахожу идею единиц измерения F # очень привлекательной. Однако часто бывает так, что некоторые единицы имеют определенный домен, в котором они живут. Например, расстояние - это положительное число, температура больше нуля Кельвина, вероятность составляет от 0 до 1 и т. Д., Но Я не видел ничего встроенного, чтобы представить это понятие и подтвердить, что определенное значение является допустимым показателем для определенной единицы. Поддерживает ли Единица измерения что-то подобное (я так не думаю), и если нет, то есть ли рекомендуемый способ реализации этого поведения?

Ответы [ 2 ]

6 голосов
/ 16 июля 2011

Единицы измерения в F # не поддерживают поведение.Это статический механизм, используемый во время компиляции для выдачи ошибок типа.Вам понадобится объект для инкапсуляции любого «поведения».Например, вы можете сделать type Temperature, который предоставляет операторы для проверки границ.Этот объект может затем вызвать исключение, если вы передадите его -1.0<Kelvin>.

Вы можете сделать что-то вроде этого.

[<Measure>] 
type Kelvin =
    static member ToCelsius kelvin =
        (kelvin - 273.15<Kelvin>) * 1.0<Celsius/Kelvin>

and [<Measure>] Celsius = 
    static member ToKelvin celsius =
        (celsius + 273.15<Celsius>) * 1.0<Kelvin/Celsius>

type Temperature(kelvin : float<Kelvin>) =
    do
        if kelvin < 0.0<Kelvin> then
            failwith "Negative Kelvin Temperature"

    member this.Celsius with get() = Kelvin.ToCelsius kelvin
    member this.Kelvin with get() = kelvin

    // could add operators here like (=) or (+)

let good = Temperature(0.0<Kelvin>)
let bad = Temperature(-1.0<Kelvin>)
3 голосов
/ 17 июля 2011

Как уже сказал gradbot, единицы измерения F # используются только во время компиляции.К сожалению, вы не можете написать условие, что значения определенной единицы должны быть, например, больше нуля (это было бы довольно сложно проверить в компиляторе).

Поскольку единицы измерения также не существуют во время выполненияВы не можете написать универсальную функцию, которая измеряет любую температуру и проверяет, имеет ли значение единицу Kelvin и меньше ли она нуля (а затем выдает исключение).Вам нужно было бы написать разные типы оболочки (например, TemperatureK для значений типа float<Kelvin>).

Лучшим вариантом может быть использование библиотеки, которая отслеживает единицы измерения во время выполнения.Затем вы можете получить модуль во время выполнения и выполнить проверку.Фил Трелфорд реализовал хорошую библиотеку единиц измерения времени выполнения , которую, возможно, стоит проверить.

...