在一行中编写F#对象表达式

时间:2014-01-01 20:59:58

标签: syntax f#

当我准备为F#编写代码生成器时,我想知道是否可以通过仅生成一行值来避免进入缩进混乱。

作为这项工作的一部分,我正在考虑如何在一行中表达对象表达式,但除了在详细模式中之外无法成功。

let Expr() = (let ToString = "ToString" in { new System.Object() with member this.ToString() = ToString; member this.GetHashCode() = ToString.GetHashCode()})

问题是我不想在详细模式下生成所有代码,这是兼容性功能。还有其他选择吗?

提前感谢您的见解!
弗朗索瓦


我要求这个的原因是我必须以任意表达式生成对象表达式,我想避免计算当前行中的字符数来计算我已经有多少缩进下一行。

2 个答案:

答案 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
]