【问题标题】:Can I Use Template Haskell to Generate Hamlet Code?我可以使用模板 Haskell 生成 Hamlet 代码吗?
【发布时间】:2016-11-26 21:40:38
【问题描述】:

我遇到了一个有趣的问题,我认为它可能与 Template Haskell 相关。我正在使用 yesod 和 yesod-persistant 开发数据库的 Web 前端。我正在使用mkPerist 函数和persistLowerCase quasi-quoter 生成我的数据库类型。 我的问题是,我需要一种编辑数据库字段的方法,但是为每列的六个不同页面编写 hamlet 代码似乎非常重复。我想我可以使用 Template Haskell 自动生成文本字段和复选框,以便在给定类型的情况下编辑数据库的该列。理想情况下,我只需将类型的名称传递给 Template Haskell 函数,然后 TH 将负责为页面生成所有 Hamlet。我的问题是,在这种情况下我可以使用 Template Haskell 吗?这是最好的解决方案吗?特别是,Template Haskell 可以为其他准引用者生成代码吗?特别是哈姆雷特?这是我现在项目的链接:https://github.com/ProspectRidgeTech/PRADatabase提前致谢! (PS。让我知道是否有更好的方法来解决这个问题,如果你对我的问题有任何建议的编辑。)

【问题讨论】:

    标签: database haskell yesod template-haskell hamlet


    【解决方案1】:

    回答你的问题:是的,你可以,但我不推荐它。准引用器只是一个函数,它接受一个字符串并生成一些代码,所以当你看到

    [hamlet|blah blah|]
    

    你可以用(或等效的)替换它

    $(hamlet "blah blah")
    

    所以没有什么能阻止你在 TH 中生成一个字符串调用 hamlet。但是,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,但是这一步不涉及 Hamlet。

    【讨论】:

    • 谢谢!我认为如果我可以在没有 TH 的情况下解决至少部分问题,那绝对是解决问题的方法!我不知道 Persistent 提供了这种类型的信息!作为一个快速跟进的问题,参数getColumn 来自哪里?我想我可以做类似(runDB $ selectList [] []) 的事情来从某个列中获取所有entities 的列表,但是(FieldDef -&gt; Text) 有什么作用呢?另外,你能把我链接到定义这些持久函数的模块吗?感谢您的所有帮助!
    • getColumn :: FieldDef -&gt; Text 只是一个从列定义中提取名称以将其用作列名的函数。我个人使用unDBName . fieldDB,但您可以更改以更改大小写。
    • 太棒了!感谢您的迅速回复!我想这就是我所需要的!再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2015-01-20
    • 2015-12-22
    • 2013-10-03
    • 2020-02-06
    相关资源
    最近更新 更多