2015-12-21 81 views
2

我想建立一个通用的函数操作记录我的代码如下所示:F#泛型记录

type Status = Active | Inactive 

type IStatus = 
    abstract member Status: Status 

type User = 
    { 
     Username : string; 
     Status : Status 
    } 
    interface IStatus with 
     member x.Status = x.Status 


let ChangeStatus<'T when 'T :> IStatus> newStatus (t:'T) = 
    {t with Status = newStatus} 

现在我得到以下错误:

expression was expected to have type 
    'T  
but here has type 
    User  

很显然,我只是想创建实现IStatus的记录的类型约束。我在想OO吗?或者是否有这种方法的优点,以及如何创建ChangeStatus函数?

谢谢您的阅读。

回答

3

我不认为你想要做什么是不可能的,因为它需要一个“通用记录克隆器”,我的意思是一个通用记录表达式,目前尚不支持。

您可以为每个子类创建一个克隆方法,该方法应该可以工作,但您必须重复该代码才能克隆该记录。这可能是一个通用的解决方案,但涉及反思。

但是,如果您更改设计,您可以获得所需的功能。例如,您可以使用一个通用的嵌套的记录:

type Status = Active | Inactive 

type StatusRecord<'T> = 
    { 
     Item : 'T 
     Status : Status 
    } 

let changeStatus newStatus t = {t with Status = newStatus} 

// TEST 

type User = {Username : string} 
type Group = {Groupname : string; members : User list} 

let user = {Status = Active; Item = {Username = "User1"}} 
let group = {Status = Active; Item = {Groupname = "Group1"; members = []}} 

这是一个非常轻量级的解决方案,你会写更少的代码,但它会改变这取决于你的代码的其余部分将是有意义还是不是你的设计。

+0

一旦你开始嵌套记录,并需要更新内部,它可以是值得看镜头。参见:http://bugsquash.blogspot.co.uk/2011/11/lenses-in-f.html和http://stackoverflow.com/questions/8179485/updating-nested-immutable-data-structures – TheInnerLight

+1

@TheInnerLight我同意。我不想让答案复杂化,但请注意,该文章中描述的镜头不是多形的。实际上[FSharpPlus](https://github.com/gmpl/FSharpPlus)中有一个多态镜头模块,如果设计合理,可能值得使用。 – Gustavo

+0

谢谢你的答案。我将需要一个周末,一个黑暗的房间和一支蜡烛来包围我的头。其中之一当然是所有“额外属性”组合的“笛卡尔乘积”。 –