2013-03-28 9 views
5

myślę, że to dobrze znane ograniczenie F #, ale nie mogłem znaleźć żadnych dobrych obejścia ...F # cytaty, tablice i własny identyfikator w konstruktorów

Więc tutaj jest kod (starałem się zrobić to jak proste, jak to możliwe, więc prawdopodobnie to wygląda to nie ma żadnego sensu):

[<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 

kompilator mówi:

błąd FS0452: notowania nie może zawierać wbudowany kod montaż lub wzorzec dopasowania na tablicach

W rzeczywistości jest to połączenie as self i gettera właściwości tablicy, który przerywa wszystko.

Tutejsze punkty to:

  • naprawdę chcę użyć tablice, bo chcę WebSharper tłumaczyć swoje kolekcje do tablic obsługi JavaScript.
  • Naprawdę potrzebuję identyfikatora w konstruktorach.
  • Naprawdę potrzebuję klas (tj. Styl funkcjonalny nie zadziała).
  • Identyfikatory dla każdej metody (member this.Foo) działają bez zarzutu.

Jednym z obejść, jaki mogę wymyślić, jest tworzenie konstruktorów jako prywatnych i stosowanie metod statycznych do konstruowania obiektów. W ten sposób nie potrzebuję as self. Ale to po prostu głupie.

Czy są jakieś lepsze opcje?


Aktualizacja:

Tutaj jest jeszcze prostszy przykład:

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

Z as self nawet nie mogę określić stałą klasą. Cóż, to właściwie osobne pytanie, ale zadam to tutaj: jak zdefiniować stałą klasy w tym konkretnym przypadku?


Odpowiedz

8

Nie sądzę, że to jest głupie. W rzeczywistości wolimy metody statycznego konstruktora dla przejrzystości, nawet w kodzie, który nie korzysta z WebSharper. W całej bazie kodu IntelliFactory rzadko, jeśli w ogóle, używamy self.

Uderzasz dwie irytujące ograniczenia kompilatora F # i cytatów. Jak podkreślić, metody statyczne może rozwiązać self problem:

[<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 

Istnieje wiele innych sposobów, aby to osiągnąć, na przykład można pozbyć ref zadnie.

Po drugie, często uzyskuje się FS0452 w kodzie ReflectedDefinition z operacjami tablicowymi, nawet w prostych statycznych metodach. Zwykle można to rozwiązać za pomocą funkcji bibliotecznych zamiast bezpośredniego dostępu do tablicy (Array.iter, Array.map).

Na drugim przykładzie, naprawdę chcesz to:

[<ReflectedDefinition>] 
module Users = 

    [<Literal>]  
    let ROOT_UID = 0 

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

[<Literal>] adnotacja pozwoli Ci wzorzec-spotkanie na swoich stałych, które mogą być przydatne, jeśli jest więcej niż jeden.

Dla swoich punktach:

  1. naprawdę chcę użyć tablice - to powinno być OK
  2. naprawdę potrzebuję poczucia identyfikator - nigdy nie jest konieczne, podobnie jak konstruktorzy nie są
  3. I naprawdę trzeba klas (tj funkcjonalny styl nie będzie działać) - na pewno nie jest prawdą
  4. per-metodą self-identyfikatorów (członek this.Foo) praca w porządku - tak, i są przydatne
+0

Statyczne konstruktory-fine.Speaking o drugim przykładzie, dobrze, prawo, stała modułu działa, ale ja w rzeczywistości jest to stała klasy, dlatego chcę umieścić w klasie. Posiadanie stałych klas w klasach (i nieprzebywanie przestrzeni nazw modułu) wydaje się rozsądną rzeczą do zrobienia. – kirelagin