2

I am trying to model a bond entity in F# using a unit of measure for the currency.

type Bond = {
     Isin: string
     Issuer: string
     Maturity: DateTime
     Price: float<???>
}

Let's assume that a static table with all the available/possible currencies is available.

type Currency = {
    Code : string
    Name : string
}

I can go for Price as float and PriceCurrency as string or even as a Currency type but I think that this is not ideal. Any ideas?

Thanasis K
  • 125
  • 6
  • 2
    Often monetary computation requires more precision than the `float` type can provide, so developers turn to the [decimal type](https://learn.microsoft.com/en-us/dotnet/api/system.decimal?view=net-5.0) instead. – Scott Hutchinson Jan 14 '21 at 19:40
  • 1
    Fair point Scott. The main point of the question though is about the use of units of measure as a currency – Thanasis K Jan 15 '21 at 09:02

1 Answers1

2

I don't think F# units of measure are a good match for this use case, since the compiler isn't aware of the currency table. If you want to use units of measure anyway, each currency would have to be hard-coded into your source, like this:

open System

[<Measure>] type Dollar
[<Measure>] type Pound

type Bond =
    {
        Isin: string
        Issuer: string
        Maturity: DateTime
    }

type DollarBond =
    {
        Bond: Bond
        Price: float<Dollar>
    }

type PoundBond =
    {
        Bond: Bond
        Price: float<Pound>
    }

let poundsPerDollar = 0.73<Pound/Dollar>

let toPoundBond (dollarBond : DollarBond) =
    {
        Bond = dollarBond.Bond
        Price = dollarBond.Price * poundsPerDollar
    }

let dollarBond : DollarBond =
    {
        Bond = {
            Isin = "My isin"
            Issuer = "My issuer"
            Maturity = DateTime.Parse("1/1/2050")
        }
        Price = 1000.0<Dollar>
    }

printfn "%A" <| toPoundBond dollarBond
Brian Berns
  • 15,499
  • 2
  • 30
  • 40
  • Well, that code would be much clearer if you defined s `type Price` as a discriminiated union of decimal and available currencies. If you add `Price:Price`to the `Bond` type you can skip DollarBond and PoundBond – Guran Jan 15 '21 at 08:17
  • Sure, that might be better. I was mainly trying to illustrate the problem with using UOM’s in this scenario. – Brian Berns Jan 15 '21 at 14:14
  • 1
    Yes certainly. And runtime UOM would kind of defeat their own purpose even if possible. I just thought that a more compact code example could put more focus on the real issue. – Guran Jan 15 '21 at 14:18
  • 1
    Thanks @brianberns. It seems that UOM is not a best fit for this one.. – Thanasis K Jan 16 '21 at 21:38
  • @ThanasisK Don't forget that currency conversion rates change over time. The example given here of converting a dollar bond to a pound bond would not be particularly useful in real life. Consider how an investor in the UK would really have to account for a dollar-denominated bond: the purchase cost, any interest payments, and the revenue from sale or redemption would all be converted at different rates, as would the value of the bond on the balance sheet at any given time. – phoog Jan 18 '21 at 15:14