如何为带度量单位的可区分联合定义map函数
看起来你在尝试给带度量单位的可区分联合CurrencyKind实现一个Map方法,但原代码有几个明显的问题需要修正,我来一步步帮你搞定:
首先先明确你的基础定义是没问题的:
[<Measure>] type USD [<Measure>] type EUR type CurrencyKind = | CurrencyUsd of decimal<USD> | CurrencyEur of decimal<EUR>
原代码的核心问题
- 匹配分支不完整:你的
match语句只处理了CurrencyUsd,漏掉了CurrencyEur的情况,这会直接导致编译错误。 - 泛型度量参数的冲突:单个泛型
<[<Measure>] 'currency>无法同时适配USD和EUR两种度量——当实例是CurrencyUsd时,'currency是USD;当是CurrencyEur时,'currency是EUR,编译器无法推断出一个能覆盖两种情况的泛型参数。
解决方案1:明确传入对应度量的处理函数
最直观的方式是让Map方法接收两个函数,分别处理USD和EUR类型,这样能清晰对应不同的分支:
type CurrencyKind = | CurrencyUsd of decimal<USD> | CurrencyEur of decimal<EUR> // 传入两个函数,分别处理USD和EUR,返回新的CurrencyKind实例 member this.Map(fUsd: decimal<USD> -> decimal<USD>, fEur: decimal<EUR> -> decimal<EUR>) : CurrencyKind = match this with | CurrencyUsd amount -> CurrencyUsd (fUsd amount) | CurrencyEur amount -> CurrencyEur (fEur amount)
使用示例:
// 给USD金额加10 let add10ToUsd (amount: decimal<USD>) = amount + 10.0m<USD> // 给EUR金额乘以2 let doubleEur (amount: decimal<EUR>) = amount * 2.0m<EUR> // 创建测试实例 let myUsd = CurrencyUsd 100.0m<USD> let myEur = CurrencyEur 50.0m<EUR> // 调用Map方法 let updatedUsd = myUsd.Map(add10ToUsd, doubleEur) // 结果:CurrencyUsd 110.0m<USD> let updatedEur = myEur.Map(add10ToUsd, doubleEur) // 结果:CurrencyEur 100.0m<EUR>
解决方案2:用静态解析类型参数实现通用版本
如果你想要一个更通用的Map方法,能适配任意符合要求的函数(只要输入输出度量一致),可以用F#的静态解析类型参数(SRTP)来做类型检查:
type CurrencyKind = | CurrencyUsd of decimal<USD> | CurrencyEur of decimal<EUR> // 用inline和SRTP来约束度量类型 member inline this.Map([<Measure>] ^measure, f: decimal<^measure> -> decimal<^measure>) : CurrencyKind = match this with | CurrencyUsd amount when typeof<^measure> = typeof<USD> -> CurrencyUsd (f (amount :?> decimal<^measure>)) | CurrencyEur amount when typeof<^measure> = typeof<EUR> -> CurrencyEur (f (amount :?> decimal<^measure>)) | _ -> failwith "传入的度量类型与当前货币类型不匹配"
使用示例:
// 通用的加10函数,适用于任意度量的decimal let add10 (amount: decimal<'u>) = amount + 10.0m<'u> let updatedUsd = myUsd.Map(USD, add10) // 结果:CurrencyUsd 110.0m<USD> let updatedEur = myEur.Map(EUR, add10) // 结果:CurrencyEur 60.0m<EUR>
总结
- 如果你的业务逻辑中只需要处理USD和EUR这两种固定货币,解决方案1更直观,类型安全,不容易出错。
- 如果需要更灵活的通用处理,解决方案2能满足需求,但要注意类型匹配的错误处理。
内容的提问来源于stack exchange,提问作者peryaudo
相关产品推荐
相关产品推荐

