Я столкнулся с интересной проблемой, которая, по моему мнению, может быть подходящим местом для Template Haskell. Я работаю над веб-интерфейсом базы данных, используя yesod и yesod-persistant. Я генерирую свои типы баз данных, используя функцию mkPerist
и квазициклер persistLowerCase
. Моя проблема в том, что мне нужен способ редактировать поля базы данных, но запись кода группы для шести разных страниц для каждого из столбцов кажется невероятно повторяющейся. Я решил, что могу использовать Template Haskell для автоматического создания текстовых полей и флажков для редактирования этого столбца базы данных с учетом типа. В идеале я просто передал бы имя типа функции Template Haskell, а затем TH позаботился бы о создании всего Гамлета для этой страницы. Мой вопрос: могу ли я использовать шаблон Haskell в этом случае? Это лучшее решение? В частности, может ли шаблон Haskell генерировать код для других квазициклов? В частности, Гамлет? Вот ссылка на мой проект на данный момент: https://github.com/ProspectRidgeTech/PRADatabase Спасибо заранее! (PS. Дайте мне знать, если есть лучший способ подойти к этой проблеме, и если у вас есть какие-либо предложения по моему вопросу.)Могу ли я использовать шаблон Haskell для генерации кода Гамлета?
ответ
Чтобы ответить на ваш вопрос: Да, вы можете, однако я бы не рекомендовал его. Квази Цитатник это просто функция, которая взять строку и сгенерировать код, так что вы, когда вы видите
[hamlet|blah blah|]
Вы можете заменить его (или эквивалент)
$(hamlet "blah blah")
Так что ничто не мешает вам в TH для генерации строки в дереве вызовов. Однако одна из точек TH - безопасность типа. Создание строки для последующего разбора вида поражения объекта. Кроме того, эта генерация кода из 2 шагов, вероятно, будет трудно отлаживать.
В любом случае, если ваша проблема заключается в генерации таблицы для постоянных объектов, я не думаю, что вам нужно TH вообще и просто используйте информацию о постоянных полях. У меня была аналогичная проблема, и я написал код, который генерирует таблицу Html для списка объектов. Это не должно быть сложно изменить.
entitiesToTable :: PersistEntity a => (FieldDef -> Text) -> [Entity a] -> Html
entitiesToTable getColumn entities = do
let eDef = entityDef (map entityVal entities)
[shamlet|
<table.table.table-bordered.table-striped class="#{unHaskellName $ entityHaskell eDef}">
<tr>
<th> Id
$forall field <- entityFields eDef
<th> #{getColumn field}
$forall Entity eit entity <- entities
<tr>
<td.id> #{renderPersistValue $ toPersistValue eit}
$forall (pfield, fieldDef) <- zip (toPersistFields entity) (entityFields eDef)
<td class="#{getHaskellName fieldDef}" > #{renderPersistValue $ toPersistValue pfield}
|]
Написание кода для обработки формы и обновления базы данных может быть более сложным и нужно TH, однако не Гамлет участвует в этом шаге.
Спасибо! Я думаю, что если я смогу решить хотя бы часть этой проблемы без TH, это, безусловно, способ ее решения! Я не знал, что Persistent предоставил такую информацию типа! В качестве быстрого последующего вопроса, откуда берется параметр 'getColumn'? Я предполагаю, что могу сделать что-то вроде '(runDB $ selectList [] [])', чтобы получить список всех «сущностей» из определенного столбца, но что делает '(FieldDef -> Text)'? Кроме того, вы могли бы связать меня с модулем, где определены эти постоянные функции? Спасибо за вашу помощь! – thelostlambda
'getColumn :: FieldDef -> Text' - это просто функция, которая извлекает имя из определения столбца, чтобы использовать его для имени столбца. Я лично использую 'unDBName. fieldDB', но вы можете изменить, например, изменить случай. – mb14
[там] (https://hackage.haskell.org/package/persistent-2.6/docs/Database-Persist-Types.html) – mb14