区分联盟内的匿名记录类型

时间:2014-02-05 21:24:00

标签: f# algebraic-data-types

F#教程包含以下代码段:

/// A record for a person's first and last name
type Person = {     
    First : string
    Last  : string
}

/// define a discriminated union of 3 different kinds of employees
type Employee = 
    | Engineer  of Person
    | Manager   of Person * list<Employee>            // manager has list of reports
    | Executive of Person * list<Employee> * Employee // executive also has an assistant

经理和执行官被描述为元组的事实冒犯了我的感情(我很容易被冒犯)。它让我觉得不那么富有表现力。我尝试按如下方式修改它们:

/// define a discriminated union of 3 different kinds of employees
type Employee = 
    | Engineer  of Person
    | Manager   of { Name: Person; Reports: Employee list }            // manager has list of reports
    | Executive of { Name: Person; Reports: Employee list; Assistant: Employee}   // executive also has an assistant

可悲的是,Manager和Executive的定义现在给出了一个错误:“不推荐使用此结构;请考虑使用单独的记录类型。”好吧,看起来很公平,我们称之为ManagerType。但等等...... ManagerType指Employee(报表部分),Employee指ManagerType(表示Manager选项)。

这里有解决方案吗?两个数据结构是否不可能相互定义?

4 个答案:

答案 0 :(得分:11)

您可以使用and定义相互依赖的类型:

    type Employee = 
    | Engineer  of Person
    | Manager   of Manager            // manager has list of reports
    | Executive of Executive
    and Manager = { Name: Person; Reports: Employee list }
    and Executive = { Name: Person; Reports: Employee list; Assistant: Employee }

答案 1 :(得分:10)

如果你正在使用F#v3.1,你可以使用named union fields [MSDN](并保护你敏感的感觉):

type Employee = 
    | Engineer  of Person
    | Manager   of Name: Person * Reports: Employee list
    | Executive of Name: Person * Reports: Employee list * Assistant: Employee

答案 2 :(得分:6)

使用type ... = ... and ... = ...

声明相互递归类型
type Employee = 
    | Engineer  of Person
    | Manager   of Manager 
    | Executive of Executive
and Manager = { Name: Person; Reports: Employee list }
and Executive = { Name: Person; Reports: Employee list; Assistant: Employee}

答案 3 :(得分:0)

从FSharp 4.6开始,您可以将Anonymous Records与联合使用。因此,可以用这种方式定义您的示例:

type Person = {     
    First : string
    Last  : string
}

type Employee =
    | Engineer of Person
    | Manager of {| Name: Person; Reports: Employee list |}
    | Executive of {| Name: Person; Reports: Employee list; Assistant: Employee |}