Объявление таблицы Opaleye без использования TemplateHaskell
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')
Но я не могу найти никакой информации о том, как заполнить эти функции вручную.
1 ответ
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"