2010-02-02 105 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