生成F#码

生成F#码,f#,code-generation,t4,code-templates,F#,Code Generation,T4,Code Templates,T4是C#/VB.NET的“官方”代码生成引擎。但是(这是四月的,但是我找不到任何新的提及)。那么,生成F#代码的好方法是什么呢 编辑: 我想在F#中实现。我已经在C#中实现了它们,所以这应该是一个很好的比较。树的“数字”和节点可以表示为数组,因此 type 't FingerTree = Empty | Single of 't | Deep of 't array * (('t FingerTree) array) lazy * 't array 但是,这些阵列的最大大小非常小,所以最好有

T4是C#/VB.NET的“官方”代码生成引擎。但是(这是四月的,但是我找不到任何新的提及)。那么,生成F#代码的好方法是什么呢

编辑:

我想在F#中实现。我已经在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的方法看起来非常适合它…

这取决于你想做什么。虽然这种方法不适合像许多T4示例所示的那样生成模板,但一般来说,我建议为F#中的代码生成或面向语言的编程任务设计一个“combinators库”[1]。其思想是设计一些组合器来表示您试图生成的代码,从组合器生成F#源文本,然后通过代码DOM进行编译

然而,通常情况下,简单地为组合器编写解释器比生成代码更容易

F#中组合子的好例子有:


[1]

我基本上同意Robert的观点(尽管在某些情况下,使用F#中的T4可能非常有用)。不管怎样,知道为什么要生成F#代码可能会很有趣?然后我们可能会建议一些典型的功能解决方案:-)。

我查看了各种选项,最后使用*.fsx脚本满足了我相对简单和静态的代码生成需求,该脚本使用带有
fprintf
的TextWriter写出生成的F代码

实际上,我确实在一些解析工作中使用了FParsec,但由于我没有将其他语法转换为F#,这两个部分之间没有什么关系。

因为F#不支持解决方案资源管理器中的自定义工具,所以可以将T4文件放在C#或Visual Basic项目中,并将其输出重定向到F#项目。以下是您如何使用:


//了解更多关于F#at的信息http://fsharp.net
模块2

澄清一下-您建议编写一个combinator库,输出类似于可转换为源代码的有差别的联合层次结构的内容,对吗?与使用FParsec本身生成代码相反,我的意思是。我只是想确保FParsec没有我不知道的隐藏特性……是的,一个好的开始应该是一个可以翻译成F#code的联合类型。FParsec只是一个combinator库的例子,至少据我所知,它不会生成F#代码。恐怕我不知道如何优雅地解决这个问题——我不久前遇到过类似的问题,也没有找到任何好方法。即使T4(或类似版本)起作用,它仍然会中断所有F#编辑时间类型检查,这将非常烦人。在OCaml中,这是由Campl4()解决的,但是对于F#没有等效的东西(我担心这方面的需求有限,特别是与其他可能的F#改进相比)。关于数组与元组的比较,我认为数组(带边界检查)的性能可能没有那么差(毕竟,CLR在很多情况下都可以避免检查)。但是,您也可以尝试使用F#列表的功能解决方案(如果您可以避免直接索引),因为非常小的列表应该非常快(但不幸的是,我没有任何数字).在这种情况下,我希望CLR可以避免大多数检查,但不是所有检查。当然,为了测试实际开销,我需要一个避免检查的版本,首先…当然喜欢那些没有评论的否决票,没有说明我的答案有什么问题。我从他们身上学到了很多!不幸的是,这会将Module2.fs添加到Library1.fsproj的底部和源fi的顺序les在F#中很重要:-(“因为F#不支持解决方案资源管理器中的自定义工具”,不确定您的意思,因为我们一直在F#项目中使用自定义工具:FsYacc、FsLex、测试生成器和其他MSbuild扩展。关于求值顺序,请在*.fsproj文件中按正确的顺序包含文件(并且不要自动更新fsproj文件),或者将它们添加到底部,并确保依赖关系通过前面的非自动生成的文件来解决。我只是把它们扔掉。这是我最近破解的东西。
<#@ 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();
    }
}

#>