I'm trying to implement a CurrencyQty type that acts like a number tagged at compile time:
data Currency = Usd | Eur | Gbp
data CurrencyQty (a :: Currency) = CurrencyQty Double deriving (Num)
And now I want to implement a generic conversion function that looks up exchange rates dynamically. Suppose I have some function
currentExchangeRate :: Currency -> Currency -> IO Double
I want to write
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty Usd x) = return x
inUsd (CurrencyQty Eur x) = fmap (*x) $ currentExchangeRate Usd Eur
inUsd (CurrencyQty Gbp x) = fmap (*x) $ currentExchangeRate Usd Gbp
Or maybe somehow
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty a x) = fmap (*x) $ currentExchangeRate Usd a
The syntax I'm using obviously isn't valid haskell... is there a way to accomplish this?
safe-money
package where this hole system is implemented and described in this blog post: ren.zone/articles/safe-money – Aedile