Запись выражения объекта 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
]