E 'possibile definire i tipi che dipendono l'uno dall'altro e sono definiti in file separati?

StackOverflow https://stackoverflow.com/questions/3983509

Domanda

Sto cercando di implementare una libreria con funzionalità di analisi estese. Ho deciso che userò fsyacc perché sapevo che dall'università. Purtroppo ho incontrato seguente problema.

Ho definito una classe per la testa di mia grammatica ( Capo ) e posizionare la sua attuazione in un unico file. Poi ho definito parser come:

...
%start head
%type <Head> head
...

Fsyacc genera modulo seeparated ( Parser ). Per avere successo deve essere compilato in seguente ordine: Head.fs Parser.fs

Al fine di rendere questa libreria simile a quello che si può trovare in .NET vorrei aggiungere una static il metodo Parse a Capo . Purtroppo avrei bisogno di fare uso di metodi da modulo parser.

So che come tipo dipendenze può essere risolto con ' e' operatore, ma è applicabile solo ai tipi definiti in un unico file.

C'è un altro modo per creare tipi che dipendono l'uno dall'altro, anche quando sono in file separati? che cercavo meccanismo di separazione dichiarazione / implementazione come quella in C / C ++, ma non potevo 't trovare nulla.

È stato utile?

Soluzione

Risposta breve: no. Non c'è modo di fare le entità reciprocamente ricorsive in più file in F # 2.0. (Questa è una cosa abbiamo in programma di indirizzo nella prossima versione del linguaggio.)

E 'possibile ovviare a questo in una varietà di modi, in genere utilizzando un punto di riferimento indiretto e mutazione. Ad esempio, il tipo di testa potrebbe avere un metodo 'InitializeParser' statico che prende un valore di funzione in una variabile globale mutevole, e quindi il metodo Parse statico definito nella testa potrebbe chiamare via che mutabile globale, e dopo il parser è in realtà definita, può andare a chiamare InitializeParser per attizzare il valore. (Se questo non ha senso, posso scriverlo in modo più dettagliato.)

Altri suggerimenti

speravo che è possibile. Dopo aver letto la risposta di Brian ho iniziato a cercare una soluzione adeguata. Io non voglio forzare gli utenti della biblioteca per chiamare qualsiasi metodo di inizializzazione. Perciò mi si avvicinò con qualcosa di differente.

Se compilatore non può risolvere le dipendenze a tempo di compilazione posso farlo da solo in fase di esecuzione. Ecco la definizione di mia DepencendciesResolver

module DependenciesResolver = 
    let GetMethod(_type, _method) =
        lazy (
            let a = System.Reflection.Assembly.GetExecutingAssembly()
            let t = a.GetType(_type)
            t.GetMethod(_method)
            )

E esempio di classi definite in file separati:

A.fs

namespace MutualRecursion
type A() =
    static member _b = DependenciesResolver.GetMethod("MutualRecursion.B", "b")
    static member b() = A._b.Value.Invoke(null, [||])

B.fs

nameespace MutualRecursion
type B =
    static member b() = 
        printf "Called b()"

Per La compilazione è: A.fs B.fs

Non puoi ovviare a questo con un 3 ° di file che raccoglie dopo questi due e si estende Capo con il nuovo metodo?

mi piacerebbe fare qualcosa di simile a quanto segue (che ho il sospetto è più o meno quello che Brian stava proponendo). Si noti che il utente non deve fare alcuna inizializzazione ingannevole -. Tipi stessi saper "legare il nodo"

Head.fs

type IParser =
  abstract Parse : string -> int // or whatever
  ...

type Head() =
  static let mutable parser = Unchecked.defaultof<IParser>
  static member internal SetParser p = parser <- p
  member x.DoSomethingCool() =
    let i = parser.Parse("something to parse")
    ...

Parser.fs

type Parser private () =
  static do
    Head.SetParser (Parser())
  interface IParser with
    member x.Parse s = 0
    ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top