2015-12-21 80 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

謝謝你的答案。我將需要一個週末,一個黑暗的房間和一支蠟燭來包圍我的頭。其中之一當然是所有「額外屬性」組合的「笛卡爾乘積」。 –