F# 返回F中相同类型的修改版本#

F# 返回F中相同类型的修改版本#,f#,F#,如果我有一个像这样的类层次结构 type Employee(name) = member val name: string = name type HourlyEmployee(name, rate) = inherit Employee(name) member val rate: int = rate type SalariedEmployee(name, salary) = inherit Employee(salary) member val salary: in

如果我有一个像这样的类层次结构

type Employee(name) =
  member val name: string = name

type HourlyEmployee(name, rate) =
  inherit Employee(name)
  member val rate: int = rate

type SalariedEmployee(name, salary) =
  inherit Employee(salary)
  member val salary: int = salary
我想要一个函数,用纯方法更新
name
字段,这怎么可能呢?几个失败的选项:

let changeName(employee: Employee) = 
  // no idea what class this was, so this can only return the base class

let changeName<'a when 'a :> Employee>(employee: 'a) =
  // 'a has no constructor

然后只需使用
语法来更改名称。但是
otherStuff:“a
显然是丑陋的、看起来像黑客的代码,所以我仍然愿意找到更好的解决方案。

如果您正在寻找既纯粹又惯用的F#,那么首先就不应该使用继承层次结构。这是一个面向对象的概念

在F#中,您可以使用代数数据类型对员工进行如下建模:

type HourlyData = { Name : string; Rate : int }
type SalaryData = { Name : string; Salary : int }

type Employee =
| Hourly of HourlyData
| Salaried of SalaryData
这将使您能够创建
Employee
值,如下所示:

> let he = Hourly { Name = "Bob"; Rate = 100 };;

val he : Employee = Hourly {Name = "Bob";
                            Rate = 100;}

> let se = Salaried { Name = "Jane"; Salary = 10000 };;

val se : Employee = Salaried {Name = "Jane";
                              Salary = 10000;}
> let se' = se |> changeName "Mary";;

val se' : Employee = Salaried {Name = "Mary";
                               Salary = 10000;}
您还可以定义一个函数,以纯粹的方式更改名称:

let changeName newName = function
    | Hourly h -> Hourly { h with Name = newName }
    | Salaried s -> Salaried { s with Name = newName }
这使您能够更改现有
员工的名称,如下所示:

> let he = Hourly { Name = "Bob"; Rate = 100 };;

val he : Employee = Hourly {Name = "Bob";
                            Rate = 100;}

> let se = Salaried { Name = "Jane"; Salary = 10000 };;

val se : Employee = Salaried {Name = "Jane";
                              Salary = 10000;}
> let se' = se |> changeName "Mary";;

val se' : Employee = Salaried {Name = "Mary";
                               Salary = 10000;}

如果你想让你的财产可写,为什么不“简单地”写
member val name=name with get,set
@Sehnsucht我应该提到,这就是我现在所做的,但我希望实现更纯粹的东西;对于大量案例,您必须为每个案例重复
|Blah b->Blah{b,Name=newName
。我想我会使用这个想法,但将其限制在
员工
记录的子字段。因此,
键入Employee={Name:string,payData:payData}
,其中
payData
是ADT。