标准做法是使用类型别名来指示参数语义吗?

时间:2011-12-21 02:49:21

标签: f# tuples naming type-alias

元组中的项目没有名称,这意味着您通常没有明确的方法来记录每个项目的含义。

例如,在这个有区别的联盟中:

type NetworkEvent =
| Message of string * string * string
| ...

我想说明第一项和第二项分别是发件人和收件人名称。做这样的事情是好习惯:

type SenderName = string
type RecipientName = string

type NetworkEvent =
| Message of SenderName * RecipientName * string
| ...

许多C / C ++库都有各种类型(例如win32.h),但在这些语言中,即使参数名在许多情况下是可选的,它仍然可以完成。 F#不是这种情况。

4 个答案:

答案 0 :(得分:11)

我认为使用类型别名进行文档编制是记录受歧视联盟的一种简单方法。我在我的许多演示中使用相同的方法(参见for example this one),我知道有些人也在生产应用程序中使用它。我认为有两种方法可以使定义更加不言自明:

使用类型别名:这样,您添加了一些在IntelliSense中可见的文档,但它不会通过类型系统传播 - 当您使用别名类型的值时,编译器会将其视为string,因此您无法在任何地方看到其他文档。

使用单例联合这是在F#编译器的某些位置使用的模式。它使信息比使用类型别名更加明显,因为类型SenderName实际上是与string不同的类型(另一方面,这可能会有一些小的性能损失):

type SenderName = SenderName of string
type RecipientName = RecipientName of string
type NetworkElement =
  | Message of SenderName * RecipietName * string

match netelem with
| Message(SenderName sender, RecipientName recipiet, msg) -> ...

使用记录:这样,您可以明确定义记录以携带联合案例的信息。这在语法上比较冗长,但它可能以最易于访问的方式添加其他信息。您仍然可以在记录上使用模式匹配,或者您可以使用点表示法来访问元素。在开发过程中添加新字段也更容易:

type MessageData = 
  { SenderName : string; RecipientName : string; Message : string }
type NetworkEvent = 
  | Message of MessageData

match netelem with
| Message{ SenderName = sender; RecipientName = recipiet; Message = msg} -> ...

答案 1 :(得分:6)

我已经在互联网和书籍上阅读了F#的票价份额,但从未见过任何人使用别名作为文档形式。所以我要说这不是标准做法。它也可以被视为代码重复的一种形式。

通常,特定的元组表示只应用作函数中的临时数据结构。如果你长时间存储一个元组或者在不同的类之间传递它,那么是时候进行记录了。

如果你打算在多个类中使用一个有区别的联合,那么按照你的建议使用记录,或者将所有方法作为限制联合的方法,如下所示。

type NetworkEvent =
    | Message of string * string * string

    static member Create(sender, recipient, message) =
        Message(sender, recipient, message)

    member this.Send() =
        math this with
        | Message(sender, recipient, message) -> 
            printf "Sent: %A" message

let message = NetworkEvent.Create("me", "you", "hi")

您可以使用records in pattern matching,因此元组实际上是一个方便的问题,随着代码的增长应该被记录替换。

如果一个有区别的联盟有一堆具有相同签名的元组,那么就该把它分成两个有区别的联盟了。这也会阻止您拥有多个具有相同签名的记录。

type NetworkEvent2 =
    | UDPMessage of string * string * string
    | Broadcast of string * string * string
    | Loopback of string * string * string
    | ConnectionRequest of string
    | FlushEventQueue

type MessageType =
    | UDPMessage
    | Broadcast
    | Loopback

type NetworkEvent =
    | Message of MessageType * string * string * string
    | ConnectionRequest of string
    | FlushEventQueue

答案 2 :(得分:1)

我认为在这种情况下,最好使用元组前两个元素的记录类型来强化订单的重要性。

对于数字,您可以使用度量单位做一些稍微优雅的事情,但这不适用于字符串

答案 3 :(得分:1)

我没有看到任何错误,但例如,string有10个别名可能会令人讨厌。如果那不打扰你,我说,继续吧。就个人而言,我希望支持以下内容:

type NetworkEvent =
| Message of SenderName:string * RecipientName:string * string
| ...

然后Intellisense可以提供一些帮助。 (编辑:投票赞成此建议here。)

如果您的案例包含多个字段或多个相同类型的字段,则可以考虑使用类层次结构。