2013-03-28 37 views
5

我認爲這是F#的一個衆所周知的限制,但我找不到什麼好的解決辦法?F#報價,陣列和在構造函數中自我標識

所以,這裏是代碼(我試圖使它作爲簡單越好,所以可能看起來它沒有任何意義):

[<ReflectedDefinition>] 
type Human (makeAName: unit -> string) as self = 
    let mutable cats : Cat array = [| |] 
    do 
     // get a cat 
     cats <- Array.append cats [| new Cat (self, makeAName()) |] 
    member this.Cats = cats 
and 
[<ReflectedDefinition>] 
Cat (owner : Human, name : string) = class end 

編譯器說:

錯誤FS0452:報價不包含內聯彙編代碼或圖案陣列

匹配

其實它是as self和數組屬性獲取器的組合,它打破了一切。

的這裏的要點是:

  • 我真的想用數組,因爲我想WebSharper到我的收藏轉化爲JavaSript陣列。
  • 我真的需要構造函數中的自我標識符。
  • 我真的需要類(即功能風格不起作用)。
  • 按方法自標識符(member this.Foo)正常工作。

我能想到的一種解決方法是將構造函數設置爲private並使用靜態方法構造對象。這樣我不需要as self。但它是愚蠢的。

有沒有更好的選擇?


更新:

這裏是一個更簡單的例子:

[<ReflectedDefinition>] 
type User (uid: int) as self = 
    let ROOT_UID = 0 
    member this.isRoot = (uid = ROOT_UID) 

隨着as self我甚至不能定義一個類常量。那麼,這實際上是一個單獨的問題,但我會在這裏問:如何在這種特殊情況下定義類常量?


回答

8

我不認爲它是愚蠢的。爲了清晰起見,我們實際上更喜歡靜態構造函數方法,即使在不使用WebSharper的代碼中也是如此。在整個IntelliFactory代碼庫中,我們很少使用self

您遇到了兩個令人討厭的F#編譯器和引用限制。正如你所指出的,靜態方法可以解決問題self

[<ReflectedDefinition>] 
type Human private (cats: ref<Cat []>) = 
    member this.Cats = !cats 

    static member Create(makeAName: unit -> string) = 
     let cats = ref [| |] 
     let h = Human(cats) 
     let cat = Cat(h, makeAName()) 
     cats := [| cat |] 
     h 

and [<ReflectedDefinition>] Cat (owner: Human, name: string) = 
    class 
    end 

還有許多其他的方式來實現這一點,例如,你可以擺脫ref間接的。

其次,您經常會在ReflectedDefinition代碼中獲得的數組操作,即使是普通的靜態方法。這通常可以通過使用庫函數而不是直接數組訪問來解決(Array.iterArray.map)。

對於第二個例子,你真的想這樣:

[<ReflectedDefinition>] 
module Users = 

    [<Literal>]  
    let ROOT_UID = 0 

    type User(uid: int) = 
     member this.isRoot = (uid = ROOT_UID) 

[<Literal>]註釋將讓你對你的常量,它可以方便的,如果有一個以上的模式匹配。

對於您的觀點:

  1. 我真的想用陣列 - 這應該是OK
  2. 我真的需要一個自我標識符 - 這是從來沒有必要,就像構造不
  3. 我真正需要的類(即實用的風格將無法正常工作) - 絕對不是真正的
  4. 每方法自標識符(成員this.Foo)做工精細 - 是的,是有用的
+0

靜態構造函數 - 很好。談到第二個例子,好的,正確的,模塊常量可以工作,但我實際上是一個類常量,這就是爲什麼我想放在類中。讓類內的類常量(而不是污染模塊名稱空間)看起來是一個合理的事情。 – kirelagin 2013-03-29 05:16:36