带有F#中语句的交叉类型记录?

问题描述 投票:3回答:1

以下代码无法编译:

type Person = 
  {
    FirstName : string
    LastName : string
  }

type Employee = 
  {
    FirstName : string
    LastName : string
    Salary : int
  }

let p : Person = 
  {
    FirstName = "Steve"
    LastName = "Jobs"
  }

let e : Employee = 
  {
    p with Salary = 1
  }

一种解决方法是编写一个助手,也许像这样:

let toEmployee (p : Person) : Employee = 
  {
    FirstName = p.FirstName
    LastName = p.LastName
    Salary = Unchecked.defaultof<_>
  }

let e : Employee = 
  {
    toEmployee p with Salary = 1
  }

但是这有点乏味。

F#提供了更好的方法吗?

例如,这在JavaScript中是很常见的事情:

const e = {
  ...p,
  salary: 1,
};
types f# record
1个回答
2
投票

作为静态类型的语言,这在F#中是不可能的,这是有意设计的。

假设您确实具有该功能,例如JS和值let e = {...p; Salary = 1}。然后,假设您重命名Person上的字段。应该推断e的类型是什么?错误消息应该怎么说?这个问题没有简单的答案,在更大的代码库中,它可能变得非常复杂且难以快速理解。

最好手动写出新记录。它稍微冗长一些,但符合F#的一般主题,即在某些维度上更加明确,因此您可以在注释类型上不那么具体(允许更多类型推断)。如果您可能对两者都非常含蓄,那么这将造成复杂性激增。


另一个可能在这里有用的选项是更改模型以将重复的字段放入单独的类型:

type Person = 
  { FirstName : string
    LastName : string }

type Employee = 
  { Person : Person
    Salary : int }

let p = 
  { FirstName = "Steve"
    LastName = "Jobs" }

let e = { Person = p; Salary = 1 }

在F#中,对类型进行建模的方式非常重要,并且会影响所有使用该类型的代码。因此,如果您的代码看上去很奇怪,请考虑是否可以改进您的类型。

© www.soinside.com 2019 - 2024. All rights reserved.