如何用“ with”解构联盟?

时间:2019-03-01 16:21:24

标签: f# with-statement discriminated-union

我在与有区别的联合使用“ with”时遇到一些问题:

type NaturalPerson = {
    FirstName: string
    LastName: string
}

type CorporateEntity = {
    Name1: string
    Name2: string option
}

type Person = 
    | Natural of NaturalPerson
    | Company of CorporateEntity

let company = Company { Name1 = "Foo Bar AG"; Name2 = Some "Baz" }

现在,我想将Name2更改为None,但是我不知道怎么做。 像这样:

let company2 = Company { company with Name2 = None }

在我的“真实示例”中,这是嵌套的,否则我可以使用正确的类型。

也许这是不可能的,因为我必须对不存在的边缘情况进行模式匹配(但是编译器不够聪明才能知道)。

2 个答案:

答案 0 :(得分:2)

这是您要执行的操作(我假设如果变量companyNaturalPerson,那么您希望它保持不变):

match company with
| Person _ -> company
| Company corpEntity -> Company { corpEntity with Name2 = None }

答案 1 :(得分:2)

如果您将其扩展一些,则更容易发现问题。实际上,命名的困难可能在于此。

let company = Company { Name1 = "Foo Bar AG"; Name2 = Some "Baz" } // Person
let company2 = Company { company with Name2 = None } // Person, but broken because expecting company to be type of CorporateEntity

因此,您尝试创建类型为CorporateEntity的{​​{1}},这是不相同的。

这有效,因为使用了正确的类型。

Person

我添加了类型并更改了名称,以使类型更加明显。 您可以为此let c1 : CorporateEntity = { Name1 = "Foo Bar AG"; Name2 = Some "Baz" } let p1 : Person = Company c1 let c2 : CorporateEntity = { c1 with Name2 = None } let p2 : Person = Company c2 ...

match

如果您想匹配某个函数,可以这样做:

match company with // <- rename company to person so it is clearer
| Natural _ -> company
| Company c -> Company { c with Name2 = None }

或更简洁地说:

let noCompanyName2 (c:CorporateEntity) = // c:CorporateEntity -> Person
    let { Name1 = n1; Name2 = _ } = c
    let company3 = Company { Name1 = n1; Name2 = None }
    company3

希望这会有所帮助。