在不使用TemplateHaskell的情况下声明Opaleye表

时间:2018-01-09 11:16:31

标签: haskell template-haskell opaleye

opaleye basic tutorial给出了如何在记录类型和查询中使用用户定义类型的示例:

data Birthday' a b = Birthday { bdName :: a, bdDay :: b }
type Birthday = Birthday' String Day
type BirthdayColumn = Birthday' (Column PGText) (Column PGDate)

birthdayTable :: Table BirthdayColumn BirthdayColumn
birthdayTable = table "birthdayTable"
    (pBirthday Birthday { bdName = tableColumn "name"
                        , bdDay  = tableColumn "birthday" })

使用pBirthday生成函数TemplateHaskell

 $(makeAdaptorAndInstance "pBirthday" ''Birthday')

makeAdaptorAndInstance中定义了TemplateHaskell

我想避免使用opaleyeData.Functor.Product.TH教程仅提及makeAdaptorAndInstance的文档,该文档仅解释instance (ProductProfunctor p, Default p a a', Default p b b', Default p c c') => Default p (Birthday a b c) (Birthday a' b' c') 生成的实例将为:

pBirthday

pBirthday :: ProductProfunctor p => Birthday (p a a') (p b b') (p c c') -> p (Birthday a b c) (Birthday a' b' c') 将具有以下类型:

String

但我找不到任何关于如何手动填写这些功能的信息。

1 个答案:

答案 0 :(得分:3)

GHC有一个-ddump-splices option来查看使用TH生成的代码。我认为这应该是有用的,因为它可能看起来不太糟糕。 (使用-ddump-to-file-dumpdir来控制输出位置。)

以下是编写它的一种方法:

instance (ProductProfunctor p, Default p a a', Default p b b') => Default p (Birthday' a b) (Birthday' a' b') where
  def :: p (Birthday' a b) (Birthday' a' b')
  def = pBirthday (Birthday def def)


pBirthday :: ProductProfunctor p =>
  Birthday' (p a a') (p b b') -> p (Birthday a b) (Birthday a' b')
pBirthday (Birthday pa pb) =
  Birthday `rmap` lmap bdName pa **** lmap bdDay pb
  -- It generalizes the applicative construct
  --   "Birthday <$> pa <*> pb"