如何定义具有度量单位的区分联合的映射函数

时间:2018-03-17 06:31:16

标签: f#

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

n = read(newsockfd, buffer, 255);
printf("Here is the message: %s\n", buffer);

但是,当我这样做时,我在[<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 下会收到以下错误:

  

FS0660 F#此代码的通用性低于其注释所需的代码   因为显式类型变量不能一般化。   它被限制为'美元'。

并在'currency的{​​{1}}下:

  

FS0001 F#计量单位'USD'与计量单位'EUR'

不匹配

有没有什么好方法可以进行这种构建?

1 个答案:

答案 0 :(得分:3)

定义泛型函数的方式,map函数的调用者定义了单位是什么,但那不对 - 你想要{{1}函数本身根据值定义单位。这可以使用接口完成,但它变得很丑陋。

在这种情况下,我认为你可以通过定义一个新的单位类型来解决这个问题,比如map

Money

作为参数传递给[<Measure>] type Money 的函数需要花费一些金钱并返还其他金额,因此您可以为其指定map类型。无论货币是美元还是欧元,decimal<Money> -> decimal<Money>功能都可以决定。在实施中,我们只需在调用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!