¿Es posible definir tipos que dependen entre sí y están definidos en archivos separados?

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

Pregunta

Estoy tratando de implementar una biblioteca con capacidades de análisis extendidos. Decidí que voy a utilizar fsyacc porque sabía que desde la universidad. Por desgracia me encontré siguiente problema.

I define una clase para la cabeza de mi gramática ( Cabeza ) y coloque su implementación en un solo archivo. A continuación, he definido como analizador:

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

Fsyacc genera módulo seeparated ( Analizador ). Para tener éxito tiene que ser compilado en el siguiente orden: Head.fs Parser.fs

Con el fin de hacer que esta biblioteca similar a lo que puedes encontrar en .NET me gustaría añadir un estática método Analizar para Cabeza . Por desgracia yo tendría que hacer uso de los métodos de Analizador módulo.

Sé que tales tipo de dependencias puede ser resuelto con ' y ' operador pero sólo es aplicable a los tipos definidos en un archivo.

¿Hay alguna otra manera de crear tipos que dependen el uno del otro, incluso cuando están en archivos separados? que estaba buscando mecanismo de separación declaración / aplicación como el de C / C ++, pero yo couldn 't encontrar nada.

¿Fue útil?

Solución

Respuesta corta: no. No hay manera de hacer las entidades mutuamente recursivas a través de múltiples archivos en C # 2.0. (Esto es algo que la intención de la dirección en la próxima versión de la lengua.)

Se puede solucionar este problema en una variedad de maneras, utilizando típicamente un punto de indirección y la mutación. Por ejemplo, el tipo de cabeza podría tener un método 'InitializeParser' estática que empuja un valor de función en una variable global mutable, y luego el método estático Parse se define en la cabeza podría llamar a través de ese mutable mundial, y después de que el analizador es en realidad definida, puede ir y llamar InitializeParser a meter en el valor. (Si eso no tiene sentido, no puedo explicarlo con más detalle.)

Otros consejos

Yo tenía la esperanza de que es posible. Después de leer la respuesta de Brian empecé a buscar una solución adecuada. No quería obligar a los usuarios de la biblioteca para llamar a cualquier método de inicialización. Por lo tanto, se me ocurrió algo diversa.

Si compilador no puede resolver las dependencias en tiempo de compilación que puedo hacerlo por mi cuenta en tiempo de ejecución. He aquí la definición de mi DepencendciesResolver

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

Y el ejemplo de las clases definidas en archivos separados:

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()"

orden Compilación es: A.fs B.fs

No puedes evitar esto con un archivo tercero que compila después de estos dos y se extiende la cabeza con el nuevo método?

Me haría algo como lo siguiente (que sospecho que es más o menos lo que Brian estaba proponiendo). Tenga en cuenta que el usuario no tiene que hacer cualquier inicialización difícil -. Los tipos mismos saben cómo "atar el nudo"

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
    ...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top