2013-03-28 13 views
5

Penso che sia una limitazione ben noto di F #, ma non ho trovato nessun buone soluzioni alternative ...F # citazioni, gli array e di auto-identificazione nei costruttori

Quindi, ecco il codice (ho cercato di renderlo il più semplice possibile, quindi probabilmente sembra che non ha alcun senso):

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

Il compilatore dice:

errore FS0452: Le citazioni non può contenere codice assembly inline o pattern matching su array

In realtà è la combinazione di as self e proprietà getter della matrice che rompe tutto.

I punti qui sono:

  • Ho molta voglia di usare le matrici, perché voglio WebSharper di tradurre le mie collezioni di matrici Javasript.
  • Ho davvero bisogno di un autoidentificatore nei costruttori.
  • Ho davvero bisogno di classi (ad esempio, lo stile funzionale non funzionerà).
  • Gli autoidentificatori per metodo (member this.Foo) funzionano correttamente.

Una soluzione che posso pensare è rendere privati ​​i costruttori e utilizzare metodi statici per costruire oggetti. In questo modo non ho bisogno di as self. Ma è solo sciocco.

Ci sono delle opzioni migliori?


Aggiornamento:

Ecco un esempio ancora più semplice:

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

Con as self non riesco nemmeno a definire una classe costante. Beh, in realtà è una domanda a parte, ma lo chiederò qui: come definire una costante di classe in questo caso particolare?


risposta

8

Non credo che sia sciocco. In realtà preferiamo metodi di costruzione statici per chiarezza, anche nel codice che non usa WebSharper. Nell'intera base di codici IntelliFactory raramente, se mai si utilizza self.

Si stanno colpendo due fastidiose limitazioni del compilatore F # e citazioni. Come fai notare, i metodi statici possono risolvere il problema 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 

ci sono molti altri modi per ottenere questo, per esempio, si può sbarazzarsi di ref indirezione.

In secondo luogo, si ottiene spesso FS0452 nel codice ReflectedDefinition con operazioni di array, anche in semplici metodi statici. Questo di solito può essere risolto utilizzando le funzioni di libreria anziché l'accesso diretto all'array (Array.iter, Array.map).

Per il secondo esempio, si vuole veramente questo:

[<ReflectedDefinition>] 
module Users = 

    [<Literal>]  
    let ROOT_UID = 0 

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

Il [<Literal>] annotazione vi permetterà di pattern-partita sul vostro costanti, che può essere utile se v'è più di uno.

Per i tuoi punti:

  1. Ho molta voglia di utilizzare le matrici - che dovrebbero essere OK
  2. ho davvero bisogno di un self-identifier - non è mai necessario, proprio come i costruttori non sono
  3. I davvero bisogno di classi (stile cioè funzionale non funzionerà) - sicuramente non è vero
  4. Per-metodo di auto-identificatori (membro this.Foo) funzionano bene - sì, e sono utili
+0

Costruttori statici-fine. Parlando del secondo esempio, bene, la costante del modulo funziona ma io in realtà è una costante di classe, ecco perché voglio inserirmi nella classe. Avere costanti di classe all'interno delle classi (e non lo spazio dei nomi dei moduli inquinanti) sembra una cosa ragionevole da fare. – kirelagin

Problemi correlati