2010-02-02 3 views
6

T4 è il motore di generazione del codice "ufficiale" per C#/VB.NET. Ma F# doesn't support it (questo è da aprile, ma non ho trovato nessuna menzione più recente). Allora, qual è un buon modo per generare il codice F #?Generazione del codice F #

EDIT:

Voglio realizzare 2-3 finger trees in F #. Li ho già implementati in C#, quindi questo dovrebbe essere un bel confronto. Le "cifre" e nodi dell'albero possono essere rappresentati come array, così

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

Tuttavia, la dimensione massima di queste matrici è molto piccola, quindi sarebbe bello avere

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 

per evitare il controllo dei limiti, ecc.

Tuttavia, scrivere tutte le funzioni su Digit e Node manualmente diventa più difficile ed è meglio generarle. E un approccio T4 sembra perfetto per questo ...

+0

mi limiterò a buttare [questo] (https://github.com/kerams/Templatus) là fuori. È qualcosa che ho hackerato insieme di recente. – nphx

risposta

7

Poiché F # non supporta gli strumenti personalizzati in soluzione explorer, è possibile posizionare i file T4 in un progetto C# o Visual Basic e reindirizzare l'output sul progetto F #. Ecco come si può fare 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

Sfortunatamente questo aggiungerà Module2.fs al * bottom * di Library1.fsproj e l'ordine dei file sorgente è importante in F # :-( –

+1

"Perché F # non supporta gli strumenti personalizzati in Solution Explorer", non è sicuro di cosa intendi per che, mentre usiamo tutti gli strumenti personalizzati nei nostri progetti F #: FsYacc, FsLex, generatori di test e altre estensioni MSbuild, per quanto riguarda l'ordine di valutazione, includere i file nell'ordine corretto nei file * .fsproj (e non aggiornare automaticamente i file fsproj), o aggiungerli in fondo e assicurarsi che le dipendenze siano risolte dai precedenti file non generati automaticamente. – Abel

6

Dipende da ciò che stai cercando di fare. Sebbene si tratti di un approccio che non è proprio adatto per la generazione di modelli nel modo in cui molti esempi T4 mostrano, in generale consiglierei di progettare una "libreria combinatori" [1] per la generazione di codice o attività di programmazione orientate alla lingua in F #. L'idea è di progettare alcuni combinatori per rappresentare il codice che si tenta di generare, generando il testo sorgente F # dai combinatori, quindi compilando questo tramite il codice DOM.

Tuttavia, spesso sarebbe più semplice scrivere un interprete per i combinatori anziché generare codice.

Buoni esempi di combinatori in F # sono:

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

+1

Giusto per chiarire: stai suggerendo di scrivere una libreria combinatoria che produca qualcosa come una gerarchia sindacale discriminata che può essere tradotta in codice sorgente, giusto? Al contrario di usare FParsec per generare codice, intendo. Voglio solo assicurarmi che non ci siano alcune funzionalità nascoste di FParsec a cui non ero a conoscenza ... –

+0

Sì, un buon punto di partenza sarebbe un tipo di unione che potrebbe essere tradotto in codice F #. FParsec era solo un esempio di una libreria combinatoria, non genera codice F #, almeno per quanto ne so. – Robert

1

Io per lo più d'accordo con Robert (anche se ci sono certamente alcune situazioni in cui usare T4 da F # potrebbe essere molto utile). Ad ogni modo, forse sarebbe interessante sapere perché vuoi generare il codice F #? Quindi potremmo forse suggerire qualche tipica soluzione funzionale al problema :-).

+0

Aggiunto il mio caso d'uso. –

+0

Temo di non avere una buona idea su come risolvere questo problema elegantemente - ho avuto un problema simile qualche tempo fa e non ho trovato nessun modo valido. Anche se T4 (o simile) funzionasse, avrebbe comunque infranto tutti i controlli di tipo F # edit-time, il che sarebbe abbastanza fastidioso. In OCaml, questo è risolto da Campl4 (http://en.wikipedia.org/wiki/Camlp4), ma non esiste una cosa equivalente per F # (e temo che vi sia solo un bisogno limitato di questo, soprattutto rispetto ad altri possibili miglioramenti di F #). –

+1

Per quanto riguarda gli array rispetto alle tuple, penso che le prestazioni degli array (con controllo dei limiti) potrebbero non essere così gravi (dopotutto, il CLR potrebbe evitare i controlli in molti casi). Tuttavia, puoi anche provare la soluzione funzionale usando le liste F # (se puoi evitare l'indicizzazione diretta), perché le liste molto piccole dovrebbero essere abbastanza veloci (ma non ho numeri, sfortunatamente). –

3

Ho dato un'occhiata alle varie opzioni e ho risolto le mie esigenze relativamente semplici e statiche di generazione del codice utilizzando uno script * .fsx che utilizza un TextWriter con fprintf per scrivere il codice F # generato.

In realtà uso FParsec per alcuni lavori di analisi, ma poiché non sto traducendo da qualche altra sintassi in F #, i due pezzi hanno poco a che fare l'uno con l'altro.

+0

Questo potrebbe essere sufficiente. –

+1

Certo, adoro quei downvotes senza un commento per dire cosa c'è che non va nella mia risposta. Imparo molto da loro! –