匿名记录类型在判别联合体中的应用

12

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个回答

17

你可以使用 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 }

有趣。我们可以使用继承吗?执行者可以从经理派生吗?还是这只适用于记录? - Phillip Scott Givens

14

如果您使用的是 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

2
这个方案并不差(它确实避免了折磨我的身体),但如果我想从经理中仅提取报告,那么在模式匹配表达式中它会是什么样子呢?使用其他解决方案,它将是:| Manager ({Reports=rep}) -> whatever - CSJ
3
我尚未安装v3.1,但根据我回答中链接的MSDN页面,应该是 | Manager (Reports=rep) -> ... - Daniel
它看起来会像这样:经理(人,报告)唯一的区别是你可以给它们命名。 - kam

8
互相递归的类型使用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}

抱歉,Lee稍微比你快一点搞定了 :) - CSJ

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 |}

为了完整性:匿名记录目前无法进行模式匹配(尚未实现)。 - Good Night Nerd Pride

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接