2010-02-02 11 views
6

T4 es el motor de generación de código "oficial" para C#/VB.NET. Pero F# doesn't support it (esto es de abril, pero no pude encontrar menciones más nuevas). Entonces, ¿cuál es una buena forma de generar código F #?Generando código F #

EDIT:

Quiero poner en práctica 2-3 finger trees en F #. Ya los he implementado en C#, por lo que esta debería ser una buena comparación. Los "dígitos" y nodos del árbol pueden ser representados como matrices, por lo

type 't FingerTree = Empty | Single of 't | Deep of 't array * (('t FingerTree) array) lazy * 't array 

Sin embargo, el tamaño máximo de estas matrices es muy pequeña, así que sería bueno tener

type 't Digit = Digit1 of 't | Digit2 of 't*'t | Digit3 of 't*'t*'t | Digit4 of 't*'t*'t*'t 
type 't Node = Node2 of 't FingerTree * 't FingerTree | Node3 of 't FingerTree * 't FingerTree * 't FingerTree 
type 't FingerTree = Empty | Single of 't | Deep of 't Digit * ('t Node) lazy * 't Digit 

para evitar la comprobación de límites, etc.

Pero luego escribir todas las funciones en Dígitos y Nodos a mano se vuelve más difícil, y es mejor generarlos. Y un enfoque similar al T4 parece perfecto para él ...

+0

Voy a tirar [esto] (https://github.com/kerams/Templatus) por ahí. Es algo que he pirateado juntos recientemente. – nphx

Respuesta

7

Como F # no admite herramientas personalizadas en el explorador de soluciones, puede colocar sus archivos T4 en un proyecto C# o Visual Basic y redirigir su salida a su proyecto F #. He aquí cómo usted puede hacerlo con T4 Toolbox:

<#@ template language="C#" hostspecific="True" debug="True" #> 
<#@ output extension="txt" #> 
<#@ include file="T4Toolbox.tt" #> 
<# 
    FSharpTemplate template = new FSharpTemplate(); 
    template.Output.Project = @"..\Library1\Library1.fsproj"; 
    template.Output.File = "Module2.fs"; 
    template.Render(); 
#> 
<#+ 
class FSharpTemplate: Template 
{ 
    public override string TransformText() 
    { 
#> 
// Learn more about F# at http://fsharp.net 

module Module2 
<#+ 
     return this.GenerationEnvironment.ToString(); 
    } 
} 

#> 
+1

Desafortunadamente esto agregará Module2.fs al * fondo * de Library1.fsproj y el orden de los archivos fuente es importante en F # :-( –

+1

"Como F # no admite herramientas personalizadas en el explorador de soluciones", no estoy seguro de lo que quiere decir con eso, como usamos herramientas personalizadas en nuestros proyectos F # todo el tiempo: FsYacc, FsLex, generadores de prueba y otras extensiones de MSbuild. Con respecto al orden de evaluación, o bien incluya los archivos en el orden correcto en los archivos * .fsproj (y no actualice archivos fsproj automáticamente), o agréguelos en la parte inferior y asegúrese de que las dependencias se resuelvan mediante archivos anteriores que no se hayan generado automáticamente. – Abel

6

Depende de lo que trates de hacer. Si bien es un enfoque que no es realmente adecuado para generar plantillas en la forma en que lo muestran muchos ejemplos de T4, en general recomendaría diseñar una "biblioteca de combinadores" [1] para generación de código o tareas de programación orientadas al lenguaje en F #. La idea es diseñar algunos combinadores para representar el código que intenta generar, generando el texto fuente F # de los combinadores, luego compilando esto a través del código DOM.

Sin embargo, a menudo sería más fácil simplemente escribir un intérprete para sus combinadores en lugar de generar código.

Buenos ejemplos de combinadores en F # son:

[1] http://en.wikipedia.org/wiki/Combinator_library

+1

Solo para aclarar: sugieres escribir una biblioteca combinadora que genere algo así como una jerarquía sindical discriminada que se pueda traducir a código fuente, ¿verdad? A diferencia del uso de FParsec para generar código, quiero decir. Solo quiero asegurarme de que no haya alguna característica oculta de FParsec que no conocía ... –

+0

Sí, un buen lugar para comenzar sería un tipo de unión que podría traducirse en código F #. FParsec era solo un ejemplo de una biblioteca combinatoria, no genera código F #, al menos hasta donde yo sé. – Robert

1

estoy básicamente de acuerdo con Robert (aunque sin duda hay algunas situaciones en las usar T4 desde F # podría ser muy útil). De todos modos, tal vez sería interesante saber ¿por qué desea generar código F #? Entonces podríamos sugerir alguna solución funcional típica para el problema :-).

+0

Agregué mi caso de uso. –

+0

Me temo que no tengo una buena idea de cómo resolver esto de manera elegante, tuve un problema similar hace algún tiempo y no encontré ninguna buena manera. Incluso si T4 (o similar) funcionara, aún así rompería todas las comprobaciones de tipo de tiempo de edición de F #, lo que sería bastante molesto. En OCaml, esto es resuelto por Campl4 (http://en.wikipedia.org/wiki/Camlp4), pero no hay nada equivalente para F # (y me temo que solo hay una necesidad limitada de esto, especialmente en comparación con otros posibles mejoras de F #). –

+1

Con respecto a las matrices frente a las tuplas, creo que el rendimiento de las matrices (con comprobación de límites) puede no ser tan malo (después de todo, la CLR podría evitar los controles en muchos casos). Sin embargo, también podría intentar una solución funcional usando listas F # (si puede evitar la indexación directa), porque las listas muy pequeñas deberían ser bastante rápidas (lamentablemente, no tengo ningún número). –

3

Miré a mi alrededor en varias opciones, y terminé con mis necesidades de generación de código relativamente simples y estáticas usando un script * .fsx que usa un TextWriter con fprintf para escribir el código F # generado.

De hecho, uso FParsec para algunos trabajos de análisis, pero como no estoy traduciendo desde otra sintaxis a F #, las dos piezas tienen poco que ver entre sí.

+0

Esto podría ser suficiente. –

+1

Claro que me encantan los votos abajo sin un comentario para decir lo que está mal con mi respuesta. ¡Aprendo mucho de ellos! –