我创建了两个度量单位,美元和欧元。我想在运行时区分它们,所以我定义了以下区分联合。然后,我想像这样定义地图函数:
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'
不匹配
有没有什么好方法可以进行这种构建?
答案 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!