F# 如何定义具有度量单位的判别并集的映射函数

F# 如何定义具有度量单位的判别并集的映射函数,f#,F#,我创建了两个度量单位,美元和欧元。我想在运行时区分它们,所以我定义了以下区分联合。然后,我想这样定义map函数: [<Measure>] type USD [<Measure>] type EUR type CurrencyKind = | CurrencyUsd of decimal<USD> | CurrencyEur of decimal<EUR> member this.Map<[<Measure>

我创建了两个度量单位,美元和欧元。我想在运行时区分它们,所以我定义了以下区分联合。然后,我想这样定义map函数:

[<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
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 } 
[]键入USD
[]欧元
货币种类=
|十进制货币
|十进制货币
成员。映射->十进制f x

FS0001 F#计量单位“美元”与计量单位“欧元”不匹配


有什么好方法可以进行此构建吗?

您定义泛型函数的方式,
map
函数的调用方定义了单位,但这不对-您希望
map
函数本身根据值定义单位。这可以使用接口来完成,但它会变得丑陋

在这种情况下,我认为您可以通过定义一种新的单位类型来很好地解决这个问题,比如说
Money

[<Measure>] type Money
这可能会给你带来你想要的安全感。如果我们计算
m+m
,这是有效的,因为单位仍然是钱,但如果计算
m*m
,则会出现编译时错误:

CurrencyUsd(10.M<_>) |> map (fun m -> m + m)
CurrencyUsd(10.M<_>) |> map (fun m -> m * m) // Type error!
CurrencyUsd(10.M)|>地图(趣味M->M+M)
CurrencyUsd(10.M)|>map(fun M->M*M)//输入错误!
作为记录,使用接口的丑陋版本如下所示:

[<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
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 } 
类型映射器=

abstract Apply->Decimal不确定您想要实现什么,但这可能会有所帮助:您正在寻找转换函数f吗?从欧元到美元,反之亦然<代码>映射
通常表示表格查找。