Copying a union case but with a different value in F#
-
13-12-2019 - |
Question
In F#, I want to construct an instance (correct terminology?) of a discriminated union based on an existing instance. Example:
type union Currency =
| Dollar of int
| Euro of int
let lowPrice = Dollar 100 (* or, it could be *) let lowPrice = Euro 100
let highPrice = (* of the same union case as lowPrice but with value 200 *)
What code could I insert in place of the comment to create that effect?
Solution
You could do
let highPrice =
let n = 200
match lowPrice with
| Dollar _ -> Dollar n
| Euro _ -> Euro n
but units of measure are probably better.
EDIT
Alternatively, maybe you want
type MoneyType = Dollar | Euro
type Currency = Currency of MoneyType * int
let lowPrice = Currency(Dollar, 100)
let highPrice =
match lowPrice with
| Currency(kind, _) -> Currency(kind, 200)
OTHER TIPS
I think for this sort of problem it is more appropriate to use units of measure - somthing like
[<Measure>] type Dollar
[<Measure>] type Euro
let lowprice = 100<Dollar>
let inline _highprice (newv:int) (oldv:int<'t>) : int<'t> =
LanguagePrimitives.Int32WithMeasure newv
let highprice = _highprice 200 lowprice
the conversion function is a little tricky but it will do what you want
You can make new union case values based on existing value of the same union case using Reflection. In order to achieve this just add instance member Same
to your discriminated union, which first derives specific union case from the instance self
and then constructs a new instance by the same union case, but now populated with newVal
:
open Microsoft.FSharp.Reflection
type Currency =
| Dollar of int
| Euro of int
member self.Same newVal : Currency =
FSharpValue.MakeUnion(fst (FSharpValue.GetUnionFields(self,
typeof<Currency>)), [|newVal|])
|> unbox
Now applying it to lowPrice
value below
let lowPrice = Euro(100)
let highPrice = lowPrice.Same 200
you'll get highPrice : Currency = Euro 200