F#: Can units of measure be bound dynamically at runtime?
I'm very new to F# and am intrigued by the Units of Measure functionality and have a rough idea of how it works normally, but would like to know if it's possible to bind measures to values where we don't know what the measure will be until the code is executing?
The practical example I'm looking at is binding floats as currency values where the unit of measure is inferred from a database lookup.
Let's assume that the measures for each currency (USD, EUR, AUD, etc) are declared normally:
[<Measure>] USD
[<Measure>] EUR
[<Measure>] AUD
...
First you would need a way to obtain a measure's type from an identifier, ideally the measure name itself as the currency code is most likely stored and retrieved as a 3-character string (similar to Enum.Parse()
).
Then you would need a way of binding a float value to the type created in the previous step.
Is this possi开发者_StackOverflow社区ble, or is there another way to achieve the same outcome?
This isn't possible, since F# units-of-measure are erased (they only exist at compile-time).
You could author a library with a runtime implementation (I haven't thought about what a design would look like). But you probably lose the static checking.
I think possibly a better strategy may be to isolate the boundary, and at the boundary point (where you read from the database and infer the unit types) somehow get the right types into the type system, but depending on how the code is structured and what exactly you're doing, that may or may not be possible/easy...
Unless you are writing code that is actually specific to one particular currency, you shouldn't explicitly mention USD, EUR, AUD etc in your code. Instead, make your code polymorphic over the currency/currencies involved.
What you have to think about is what kinds of safety you are expecting to get from units of measure. If for example (in a very simplistic scenario) you would be reading from a database field, doing some processing and writing back to that same field, then having a function of type float<'a> -> float<'a>
is exactly what you want: you don't care what the currency is, so long as you get back the same one you put in.
精彩评论