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

CSJ*_*CSJ 9 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
Run Code Online (Sandbox Code Playgroud)

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

/// 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
Run Code Online (Sandbox Code Playgroud)

遗憾的是,Manager和Executive的定义现在给出了一个错误:"不推荐使用此构造;请考虑使用单独的记录类型." 好吧,看起来很公平,我们称之为ManagerType.但是等待...... ManagerType指的是Employee(对于Reports部分),Employee指的是ManagerType(对于Manager选项).

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

Lee*_*Lee 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 }
Run Code Online (Sandbox Code Playgroud)


Dan*_*iel 10

如果你正在使用F#v3.1,你可以使用命名联合字段[MSDN](并保护你敏感的感觉):

type Employee = 
    | Engineer  of Person
    | Manager   of Name: Person * Reports: Employee list
    | Executive of Name: Person * Reports: Employee list * Assistant: Employee
Run Code Online (Sandbox Code Playgroud)

  • 我没有安装v3.1,但根据我的回答中链接的MSDN页面,它将是`| 经理(Reports = rep) - > ...`. (3认同)
  • 这个解决方案还不错(它确实避免了我虚弱的体质的困扰),但是如果我只想从经理那里提取报告,那么在模式匹配表达式中会是什么样子?使用其他解决方案将是:`| 经理 ({Reports=rep}) -&gt; 随便`。 (2认同)

kvb*_*kvb 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}
Run Code Online (Sandbox Code Playgroud)


Jon*_*Job 6

从 FSharp 4.6 开始,您可以将匿名记录与联合一起使用。因此,您的示例可以这样定义:

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 |}
Run Code Online (Sandbox Code Playgroud)