0

opaleye基础教程给出了一个关于如何在记录类型和查询中使用用户定义类型的例子:

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中的定义在哪里Data.Functor.Product.TH

我想避免使用TemplateHaskell. opaleye教程只是参考了 的文档,Data.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')

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

4

1 回答 1

3

GHC 可以-ddump-splices选择查看使用 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"
于 2018-01-09T11:39:33.330 回答