2009-09-09 7 views
3

Cette question est étroitement liée à celles-ci (1, 2, 3)F # Ununit - reunit dans une fonction

J'utilise une bibliothèque externe qui doens't (encore) gérer les unités de mesure. Je veux pouvoir «ununir» les valeurs avant de les transmettre, puis les «réunir» quand je récupère les résultats. Le hic, c'est que je voudrais éviter d'être obligé de déclarer QUELLES unités à l'avance.

Exemple d'extrait

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 

Je n'ai pas réussi à déterminer comment gérer celui-ci ...

Mise à jour Si je understood correctly, la version finale de F # comprendra des fonctions pour faire ça.

+0

Le CTP mai/2010 Beta 1 version a des unités de mesure support pour les types intégraux signés - voir 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 –

Répondre

1

Pour l'instant, la boxe et casting semble fonctionner:

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

Je ne serais pas surpris si les unités de trucs de mesure passe par d'autres changements avant la libération, mais, ce qui pourrait briser ce. Vous pouvez également faire une version plus générique, par exemple:

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

EDIT

Il y a maintenant une fonction FloatWithMeasure à 'jeter aux unités':

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

+0

Excellent, merci beaucoup! J'aime vraiment la deuxième option, même si je pense que je l'appellerai unitize (comme memoize). – Benjol

0

Et juste pour le plaisir , voici le contraire:

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

Test:

#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 

Des trucs bizarres avec ça # "(£ $! Erreur de restriction de valeur si vous exécutez let withunits = reunit nounits seul. Donc, vous devez l'exécuter avec la ligne qui utilise withunits. Je suppose que ce n'est pas surprenant, vous devez passer dans le (v:float<'u>) pour se réunir pour F # pour être en mesure de déterminer ce que vous êtes. Peut-être fait reunit d'un intérêt limité, je suppose ...

MISE À JOUR: Une solution de contournement légèrement loufoque est de passer « modèle » des valeurs

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>