2009-09-09 4 views
3

Этот вопрос тесно связан с этим из них (1, 2, 3)F # Ununit - reunit внутри функции

Я использую внешнюю библиотеку, которая doens't (пока) обрабатывать единицы измерения. Я хочу иметь возможность «отключать» значения, прежде чем передавать их, а затем «воссоединить» их, когда верну мне результаты.

Уловка заключается в том, что я хотел бы избежать принуждения объявлять единицы 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 

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

Update Если у меня есть understood correctly, окончательный вариант F # будет включать в себя функции сделать это.

+0

майского CTP/2010 Beta 1 релиз имеет единицы измерения поддержка подписанных интегральных типов - см. http://blogs.msdn.com/dsyme/archive/2009/05/20/detailed-release-notes-for-the-f-may-2009-ctp-update-and- visual-studio-2010-beta1-releases.aspx –

ответ

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

EDIT

Существует теперь FloatWithMeasure функция 'отливать в единицах':

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

+0

Отлично, спасибо вам большое! Мне очень нравится второй вариант, хотя я думаю, что я его унифицирую (например memoize). – Benjol

0

И просто для удовольствия , здесь находится обратное:

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 на свой собственный. Таким образом, вы должны запустить его с помощью строки, использующей withunits. Я думаю, это не удивительно, вы должны пройти в (v:float<'u>), чтобы воссоединиться для F #, чтобы иметь возможность выработать то, что есть. Возможно, делает reunit ограниченного интереса, я думаю ...

UPDATE: Слегка свихнувшееся временное решение перейти в «модели» значение

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>