F# has a units of measure capability, described at http://msdn.microsoft.com/en-us/library/dd233243.aspx as follows:
[<Measure>] type unit-name [ = measure ]
This allows units to be defined such as:
type [<Measure>] USD
type [<Measure>] EUR
And code to be written as:
let dollars = 25.0<USD>
let euros = 25.0<EUR>
// Results in an error as the units differ
if dollars > euros then printfn "Greater!"
It also handles conversions (I'm guessing that means Measure has some functions defined that let Measures be multiplied, divided and exponentiated):
// Mass, grams.
[<Measure>] type g
// Mass, kilograms.
[<Measure>] type kg
let gramsPerKilogram: float<g kg^-1> = 1000.0<g/kg>
let convertGramsToKilograms (x: float<g>) = x / gramsPerKilogram
My instincts tell me it should be possible to implement a similar capability in Haskell, but I've not been able to find any examples of how to do it.
Edit: oh my word it's a huge can of worms! There's a research paper at http://research.microsoft.com/en-us/um/people/akenn/units/CEFP09TypesForUnitsOfMeasure.pdf. I'm guessing it's more than a few lines of code to implement the whole thing. Summer project anyone? :)
The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.
Composing functions is a common and useful way to create new functions in Haskell. Haskell composition is based on the idea of function composition in mathematics. In mathematics, if you have two functions f(x) and g(x), you compute their composition as f(g(x)). The expression f(g(x)) first calls g and then calls f.
Wrap numbers in a newtype and give them a Num
instance.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype GBP n = GBP n deriving (Show, Num, Eq, Ord)
newtype USD n = USD n deriving (Show, Num, Eq, Ord)
Usage:
ghci> let a1 = GBP 2
ghci> let a2 = GBP 5
ghci> a1 + a2
GBP 7
ghci> let b1 = USD 3
ghci> let b2 = USD 6
ghci> b1 + b2
USD 9
ghci> a1 + b2 -- should be an error for mixing currencies
<interactive>:8:6:
Couldn't match expected type `GBP Integer'
with actual type `USD Integer'
In the second argument of `(+)', namely `b2'
In the expression: a1 + b2
In an equation for `it': it = a1 + b2
The dimensional and dimensional-tf (with type families instead of multi-parameter type classes) libraries are pretty nice and can handle most of the issues presented in your example.
I don't think the library lets you define custom dimensions like currencies, though. As far as I know you would need to modify the library code to do that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With