当我准备为F#编写代码生成器时,我想知道是否可以通过仅生成一行值来避免进入缩进混乱。
作为这项工作的一部分,我正在考虑如何在一行中表达对象表达式,但除了在详细模式中之外无法成功。
let Expr() = (let ToString = "ToString" in { new System.Object() with member this.ToString() = ToString; member this.GetHashCode() = ToString.GetHashCode()})
问题是我不想在详细模式下生成所有代码,这是兼容性功能。还有其他选择吗?
提前感谢您的见解!
弗朗索瓦
我要求这个的原因是我必须以任意表达式生成对象表达式,我想避免计算当前行中的字符数来计算我已经有多少缩进下一行。
答案 0 :(得分:3)
(无耻插件)我维护F# source code formatter,公开APIs以完全打印完整的F#3.0语法。您有几种选择:
使用详细模式实现代码生成器,并在输出上运行源代码格式化程序API。然后你不必担心缩进和详细模式上的换行很容易。
使用功能组合器实现代码生成器。您可以复制和修改许多combinators in FormatConfig module。 F#缩进规则是明确的;您可以在this article中阅读更多内容。
你可能有一个漂亮的打印AST。如果您更喜欢轻量级解决方案,则F#Compiler CodeDom有similar combinators代码生成。
答案 1 :(得分:2)
严格来说,这并不是一个答案,但是如果用适当的缩进来写它有什么不好的呢?您始终可以创建生成的行列表,并在单独的步骤中添加缩进。这就是我通常生成代码的方式,即使语言(例如HTML)不需要缩进。
为什么生成的代码必须难以辨认?正确的缩进使得生成的代码更容易查看,如果您将生成的源提交给源代码控制,您甚至可以使用通常的diff工具。
至少根据我的经验,适当的缩进实际上远没有人想象的那么困难,特别是在生成时。不要忘记,您在生成过程中掌握了所有上下文,因此添加一定程度的缩进应该非常容易。
let indent = List.map (sprintf " %s")
[
yield "let Expr() ="
yield! [
yield "let ToString = \"ToString\""
yield "{"
yield! [
"new System.Object() with"
"member this.ToString() = ToString"
"member this.GetHashCode() = ToString.GetHashCode()"
] |> indent
yield "}"
] |> indent
]