How to define a display function for discriminated union with units

I created two units of measure, USD and EUR. I wanted to distinguish between them at runtime, so I defined the following discriminatory union. Then I want to define a display function as follows:

[<Measure>] type USD
[<Measure>] type EUR
type CurrencyKind =
    | CurrencyUsd of decimal<USD>
    | CurrencyEur of decimal<EUR>

    member this.Map<[<Measure>] 'currency> (f : decimal<'currency> -> decimal<'currency>) =
        match this with
        | CurrencyUsd x -> f x
        | CurrencyEur x -> f x

However, when I do this, I get the following error in 'currency:

FS0660 F # This code is less general than required by its annotations because an explicit type variable cannot be generalized. This was limited to the dollar.

and under xof CurrencyEur x -> f x:

FS0001 F # Unit of measurement "USD" does not correspond to unit of measurement "EUR"

Is there a good way to do this assembly?

+4
source share
1 answer

, map , , , , map , . , .

, , , , Money:

[<Measure>] type Money

, map, , decimal<Money> -> decimal<Money>. USD EUR, -, map. USD EUR Money f, :

let map (f : decimal<Money> -> decimal<Money>) input =
  match input with
  | CurrencyUsd x -> CurrencyUsd((f (x * 1M<Money/USD>)) * 1M<USD/Money>)
  | CurrencyEur x -> CurrencyEur((f (x * 1M<Money/EUR>)) * 1M<EUR/Money>)

, , . m + m, , - , m * m, :

CurrencyUsd(10.M<_>) |> map (fun m -> m + m)
CurrencyUsd(10.M<_>) |> map (fun m -> m * m) // Type error!

, :

type Mapper = 
  abstract Apply<[<Measure>] 'm> : decimal<'m> -> decimal<'m>

let map (f : Mapper) input =
  match input with
  | CurrencyUsd x -> CurrencyUsd(f.Apply x)
  | CurrencyEur x -> CurrencyEur(f.Apply x)

CurrencyUsd(10.M<_>) |> map { new Mapper with member x.Apply m = m + m } 
CurrencyUsd(10.M<_>) |> map { new Mapper with member x.Apply m = m * m } 
+3

Source: https://habr.com/ru/post/1694998/


All Articles