let calcDiscount =
function
| Percentage p -> subtotal * (decimal p / 100M)
| FixedAmount f -> f
And then:
let totalDiscount =
discount
|> Option.map calcDiscount
|> Option.defaultValue 0M
F# is missing some of the convenience operators, but you could easily add these yourself if you wanted:
let (?) x f = Option.map f x
let (|?) x y = Option.defaultValue y x
and so totalDiscount becomes:
let totalDiscount = discount ? calcDiscount |? subtotal
The benefit of DU's over inheritance for me is that you can't tie yourself to any additional details that get stuck onto Discount (since you can't extend DU's). If you have loosely coupled data you won't have sort-of-relevant methods possibly mutating shared state. The discount calc only takes a simple thing hidden away by the Discount DU, and so there are fewer plates you're trying to keep spinning in your head (all of "what could be").
Inheritance isn’t necessary here. You achieve the same loose coupling with interfaces and you gain the benefit of your Order type not having to know how to calculate every single discount.