2010-02-02 184 views
6

T4是C#/ VB.NET的「官方」代碼生成引擎。但F# doesn't support it(這是從四月,但我找不到任何新的提及)。那麼生成F#代碼的好方法是什麼?生成F#代碼

編輯:

我想要實現在F#2-3 finger trees。我已經在C#中實現了它們,所以這應該是一個很好的比較。該樹的「數字」和節點可以表示爲數組,所以

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

然而,這些陣列的最大尺寸非常小,所以它會是不錯的

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 

爲了避免邊界檢查等

但隨後手寫上的數字和節點的所有功能變得更加困難,這是更好地生成它們。而T4式的方法看起來非常完美...

+0

我就扔[這](https://github.com/kerams/Templatus)在那裏。這是我最近一起入侵的東西。 – nphx 2016-01-25 10:15:06

回答

7

由於F#不支持自定義工具在Solution Explorer中,你可以把你的T4文件在C#或Visual Basic項目,它們的輸出重定向到您的F#項目。這裏是你如何可以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

不幸的是,這會將Module2.fs添加到Library1.fsproj的*底部*,並且源文件的順序在F#中很重要:-( – 2010-04-11 17:09:26

+1

「因爲F#不支持解決方案資源管理器中的自定義工具」,不確定您的意思是因爲我們一直在我們的F#項目中使用自定義工具:FsYacc,FsLex,測試生成器和其他MSbuild擴展。關於評估順序,或者在* .fsproj文件中以正確順序包含文件(和不要自動更新fsproj文件),或者在底部添加它們,並確保依賴項通過先前的非自動生成的文件解決。 – Abel 2014-10-29 18:10:42

6

這取決於你想要做什麼。雖然這是一種不適合用於生成模板的方法,但通常我會建議在F#中爲代碼生成或面向語言的編程任務設計一個「組合器庫」[1]。我們的想法是設計一些組合器來表示您嘗試生成的代碼,從組合器生成F#源代碼文本,然後通過代碼DOM編譯代碼。

然而,通常簡單地爲您的組合器編寫解釋器而不是生成代碼會更容易。

在F#組合子的例子有:

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

+1

只是爲了澄清 - 你建議編寫一個combinator庫,輸出類似區分的聯盟層次結構,可以轉換爲源代碼,對吧?我的意思是,與使用FParsec本身生成代碼相反。我只是想確保沒有FParsec的一些隱藏功能,我沒有意識到... – 2010-02-02 22:29:51

+0

是的,一個好的開始是一個可以轉換成F#代碼的聯合類型。 FParsec只是一個combinator庫的例子,至少就我所知,它並不生成F#代碼。 – Robert 2010-02-03 06:06:06

1

我大多與羅伯特同意(雖然肯定有某些情況下使用F#中的T4可能非常有用)。無論如何,也許這將是有趣的知道爲什麼你想生成F#代碼?那麼我們可以建議一些典型的功能解決方案:-)。

+0

添加了我的用例。 – 2010-02-03 08:20:51

+0

恐怕我沒有什麼好主意如何優雅地解決這個問題 - 前段時間我有類似的問題,沒有找到任何好的方法。即使T4(或類似)工作,它仍然會打破所有F#編輯時類型檢查,這將是非常煩人的。在OCaml中,這是由Campl4(http://en.wikipedia.org/wiki/Camlp4)解決的,但是F#沒有相同的東西(我恐怕只有有限的需求,尤其是與其他可能的F#改進)。 – 2010-02-03 15:21:00

+1

關於數組和元組 - 我認爲數組的性能(帶邊界檢查)可能不會那麼糟糕(因爲在許多情況下,CLR可以避免檢查)。但是,您也可以嘗試使用F#列表的功能性解決方案(如果您可以避免直接編制索引),因爲非常小的列表應該非常快(但不幸的是,我沒有任何數字)。 – 2010-02-03 15:23:32

3

我環顧了各種選項,結束了我使用* .fsx腳本使用TextWriter與fprintf寫出生成的F#代碼的相對簡單和靜態的代碼生成需求。

其實我使用FParsec一些分析工作,但因爲我不是從一些其他的語法爲F#轉換,將兩片幾乎沒有什麼彼此。

+0

這可能就足夠了。 – 2010-02-03 08:25:17

+1

當然,如果沒有評論的話,那些愛不釋手的人會說我的答案有什麼問題。我從他們那裏學到很多東西! – 2010-02-03 18:33:00