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

Rei*_*aka 13 f# naming tuples type-alias

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

例如,在这种受歧视的联盟中:

type NetworkEvent =
| Message of string * string * string
| ...
Run Code Online (Sandbox Code Playgroud)

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

type SenderName = string
type RecipientName = string

type NetworkEvent =
| Message of SenderName * RecipientName * string
| ...
Run Code Online (Sandbox Code Playgroud)

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

Tom*_*cek 11

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

使用类型别名:这样,您添加一些在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) -> ...
Run Code Online (Sandbox Code Playgroud)

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

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

match netelem with
| Message{ SenderName = sender; RecipientName = recipiet; Message = msg} -> ...
Run Code Online (Sandbox Code Playgroud)

  • 基于上调,这可能是一个少数人的观点,但记录或单一案例联盟的冗长在我看来是一个交易破坏者.它完全否定了工会的简洁/语法方便.这似乎是Intellisense最好解决的一个问题 - 前提是有一种注释字段的方式 - 不改变你的类型和编码风格. (3认同)
  • 我认为这个(非常好的)答案可能需要更新.你现在可以做``X = Msg Sender:string*Recip:string`.你也可以使用这些字段:`let x = X(Sender ="Foo",Recip ="Bar")`.就像记录一样,但语法不同. (2认同)

gra*_*bot 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")
Run Code Online (Sandbox Code Playgroud)

您可以在模式匹配中使用记录,因此元组实际上是方便的,随着代码的增长应该被记录替换.

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

type NetworkEvent2 =
    | UDPMessage of string * string * string
    | Broadcast of string * string * string
    | Loopback of string * string * string
    | ConnectionRequest of string
    | FlushEventQueue
Run Code Online (Sandbox Code Playgroud)

type MessageType =
    | UDPMessage
    | Broadcast
    | Loopback

type NetworkEvent =
    | Message of MessageType * string * string * string
    | ConnectionRequest of string
    | FlushEventQueue
Run Code Online (Sandbox Code Playgroud)