Запись выражения объекта F# в одну строку

Когда я собирался написать генератор кода для F#, мне было интересно, смогу ли я избежать вмешательства в отступы, генерируя только однострочные значения.

В рамках этой работы я размышлял о том, как можно выразить объектные выражения в одной строке, но не смог добиться успеха, кроме как в режиме Verbose.

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

Проблема в том, что я не хочу генерировать весь свой код в режиме Verbose, это функция совместимости. Есть ли другой вариант?

Большое спасибо заранее за ваши идеи!
Франсуа


Причина, по которой я спрашиваю об этом, состоит в том, что я должен генерировать объектные выражения в произвольных выражениях, и я хотел бы избежать подсчета количества символов в текущей строке, чтобы вычислить, сколько я должен сделать отступ для следующей строки.

2 ответа

Решение

(Бесстыдный плагин). Я поддерживаю средство форматирования исходного кода F#, которое предоставляет API-интерфейсам полный синтаксис F# 3.0. У вас есть несколько вариантов:

  • Реализуйте генератор кода, используя подробный режим, и запустите API форматирования исходного кода на выходе. Тогда вам не нужно беспокоиться об отступе, и разрыв строки в подробном режиме очень прост.

  • Реализуйте свой генератор кода, используя функциональные комбинаторы. В модуле FormatConfig есть много комбинаторов, которые вы можете копировать и изменять. Правило отступа F# понятно; Вы можете прочитать больше в этой статье.

  • У вас, вероятно, есть AST для красивой печати. Если вы предпочитаете легкое решение, у F# Compiler CodeDom есть аналогичные комбинаторы для генерации кода.

Строго говоря, это не ответ, но что плохого в том, чтобы написать его с правильным отступом? Вы всегда можете составить список сгенерированных строк и добавить отступ в отдельном шаге. Именно так я обычно генерирую код, даже если язык (например, HTML) не требует отступов.

Почему сгенерированный код должен быть неразборчивым для людей? Правильный отступ облегчает просмотр сгенерированного кода, и вы даже можете использовать обычные инструменты сравнения, если, например, сгенерированные источники переданы в систему контроля версий.

По крайней мере, по моему опыту, правильный отступ на самом деле гораздо менее сложен, чем можно подумать, особенно при генерации. Не забывайте, что у вас есть весь контекст во время генерации, поэтому добавить уровень отступа должно быть очень легко.

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
]
Другие вопросы по тегам