F # Ununit - воссоединиться внутри функции

Этот вопрос тесно связан с этими (1, 2, 3)

Я использую внешнюю библиотеку, которая еще не обрабатывает единицы измерения. Я хочу иметь возможность "деактивировать" значения, прежде чем передавать их, а затем "воссоединить" их, когда я верну результаты.

Уловка заключается в том, что я бы хотел, чтобы вы не были вынуждены заранее объявлять единицы WHICH.

Пример фрагмента

let ExternalNonUnitAwareFunction s = s + 1.

let MyUnitAwareClient (s:float<'u>) =  //'
    //1. this option "flattens" to no unit, or fixes to first inferred unit
    //let (unit:float<'u>) = 1.0<_>  
    //2. this works fine, except for 0!
    let unit = s / (float s) 
    s |> float |> ExternalNonUnitAwareFunction |> (*) unit

Мне не удалось разобраться, как справиться с этим...

Обновление Если я правильно понял окончательная версия F # будет включать в себя функции для этого.

Ответы

Ответ 1

В настоящее время бокс и литье срабатывают:

let MyUnitAwareClient (s:float<'u>) =  
  let result = s |> float |> ExternalNonUnitAwareFunction
  (box result :?> float<'u>)

Я не удивлюсь, если единицы измерения будут проходить некоторые дальнейшие изменения до релиза, хотя это может нарушить это. Вы также можете сделать более общую версию, например:

let reunit (f:float -> float) (v:float<'u>) =
  let unit = box 1. :?> float<'u>
  unit * (f (v/unit))

ИЗМЕНИТЬ

Теперь существует функция FloatWithMeasure для "cast to units":

http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx

Ответ 2

И просто для удовольствия, вот что противоположное:

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

Тест:

#light

[<Measure>]type mm

let reunit (fn:float -> float) (v:float<'u>) =
    let unit = box 1. :?> float<'u>
    unit * (fn(v/unit))

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

let nounits v = v + 2.5            //function with no units
let withunits = reunit nounits     //make it handle units (run with next line)
withunits 2.5<mm>                  //try it -> 5.0<mm>

let newnounits = deunit withunits  //remove unit handling
newnounits 2.5                     //try it -> 5.0<mm>

let withunits2 = reunit newnounits //reunit to another function
withunits2 2.5<mm^2>               //try with different units

Странный материал с этой # "(£ $! Ошибка ограничения значения там, если вы запустили let withunits = reunit nounits на свой собственный. Таким образом, вам нужно запустить его с помощью строки, использующей с помощью. Я думаю, это не удивительно, вам нужно пройдите в (v:float<'u>), чтобы воссоединиться для F #, чтобы иметь возможность выработать то, что у вас. Возможно, делает воссоединение с ограниченным интересом, я думаю...

ОБНОВЛЕНИЕ: Некорректное обходное решение - передать значения 'model'

let reunit2 (fn:float -> float) (model:float<'u>*float<'v>) =
    let unitin = box 1. :?> float<'u>
    let unitout = box 1. :?> float <'v>
    (fun v -> (fn(v / unitin)) * unitout)

let withunits3 = reunit2 nounits (0.<mm>, 0.<mm^2>)
withunits3 3.5<mm>