如何减少此 F# 代码中的重复模块?

How do I reduce the duplicated modules in this F# code?

我正在开发一个新系统,我在其中为我的实体使用强类型的 Id 值。为此,我遵循了我之前看到的推荐模式。虽然代码看起来很重复,但我想简化它。

type PersonId = private PersonId of string
module PersonId =
    let private prefix = "person"
    let value (PersonId id) = id
    let create (id: string) = PersonId(sprintf "%s_%s" prefix id)

type OrderId = private OrderId of string
module OrderId =
    let private prefix = "order"
    let value (OrderId id) = id
    let create (id: string) = OrderId(sprintf "%s_%s" prefix id)

有没有办法让这段代码更通用,这样我就不必重复模块代码了?我正在考虑制作 PersonIdOrderId 类型的 EntityId 可区分联合,但不确定 EntityId 模块代码可能是什么样子。感谢您的帮助。

我认为你正朝着这样的方向发展:

type EntityId =
    private
    | PersonId of string
    | OrderId of string

module EntityId =
    let init makeEntity prefix =
        fun id -> makeEntity (sprintf "%s_%s" prefix id)
    let value = function
        | PersonId id
        | OrderId id -> id

这里的技巧是 init 函数用于使您当前的 create 函数像这样:

module PersonId =
    let create = EntityId.init PersonId "person"

module OrderId =
    let create = EntityId.init OrderId "order"

然后你可以这样使用它:

let personId = PersonId.create "abc"
let orderId = OrderId.create "xyz"

printfn "%A" personId
printfn "%A" orderId

printfn "%s" <| EntityId.value personId
printfn "%s" <| EntityId.value orderId

输出为:

PersonId person_abc
OrderId order_xyz
person_abc
order_xyz

P.S。如果你喜欢柯里化,你可以将 init 简化为:

let init makeEntity prefix id =
    makeEntity (sprintf "%s_%s" prefix id)