Ведение единиц измерения в типовых разговорах - PullRequest
2 голосов
/ 23 февраля 2012

Если мы определим единицу измерения как:

[<Measure>] type s

, а затем целое число с мерой

let t = 1<s>

, а затем преобразовать его в число с плавающей точкой

let r = float t

мы видим, что r = 1.0 без типа меры. Это кажется очень странным, так как вся информация о мерах была потеряна.

Вы можете использовать LanguagePrimitives.FloatWithMeasure, чтобы преобразовать обратно в число с плавающей точкой, например

let inline floatMeasure (arg:int<'t>) : (float<'t>) =
    LanguagePrimitives.FloatWithMeasure (float arg)

, который обеспечивает правильные типы, но это не похоже на правильное решение, как документы для единиц измерения (http://msdn.microsoft.com/en-us/library/dd233243.aspx) скажем

Однако для написания слоев взаимодействия есть также некоторые явные функции, которые вы можете использовать для преобразования безразмерных значений в значения с единицами измерения. Они находятся в модуле Microsoft.FSharp.Core.LanguagePrimitives. Например, чтобы преобразовать число с плавающей запятой в число с плавающей запятой, используйте FloatWithMeasure, как показано в следующем коде.

Что, по-видимому, предполагает, что этой функции следует избегать в коде F #.

Есть ли более идиоматический способ сделать это?

Ответы [ 2 ]

1 голос
/ 24 февраля 2012

Вот рабочий фрагмент, который делает именно то, что вам нужно, хотя выдает предупреждение

stdin (9,48): предупреждение FS0042: эта конструкция устарела: она используется только в библиотеке F #)):

[<NoDynamicInvocation>]
let inline convert (t: int<'u>) : float<'u> = (# "" t : 'U #)

[<Measure>] type s
let t = 1<s>
let t1 = convert t // t1: float<s>

Однако я бы не предложил этот подход.
Прежде всего, UoM - это время компиляции, а преобразование типов let r = float t - время выполнения.В момент вызова int -> float понятия не имеет, является ли он int<s> или int<something_else>.Так что просто невозможно определить правильный float<'u> во время выполнения .

Другая мысль состоит в том, что философия, лежащая в основе UoM, шире, чем она описана.Это все равно, что сказать компилятору: «Ну, это int, но, пожалуйста, относитесь к нему как int<s>».Цель состоит в том, чтобы избежать случайного неправильного использования (например, добавив int<s> к int<hours>).
Иногда нет смысла конвертировать int -> float: подумайте о int<ticks>, нет смысла float<ticks>.

Подробнее , кредит @kvb за указание на эту статью.

1 голос
/ 23 февраля 2012

(Предостережение: я не использовал единицы в гневе.)

Я думаю, что единственный минус для использования, например. FloatWithMeasure - аспект приведения единиц (от единицы к единице). Я думаю, что это концептуально ортогонально аспекту преобразования числовых представлений (например, от int до float). Однако нет (я думаю) никакой библиотечной функции, которая бы выполняла приведение числовых представлений к единичным значениям. Возможно, это отражает тот факт, что большинство единичных значений моделируют непрерывные значения реального мира, так как такие дискретные представления, как int, обычно для них не используются (например, 1<s> кажется неправильным; конечно, вы имеете в виду 1.0<s>).

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

(В любом случае мне нравится ваша floatMeasure функция, которая не смешивает аспект модуля с аспектом представления, так что если вам нужно только изменить представление, у вас есть способ выразить его напрямую .)

...