我有一个非常简单的用例,我有一个基本类型,但为了在我的数据模型中我的各种记录类型的目的,我希望每个记录都有这种类型的包装版本:
type UID = Integer
-- specialised version
newtype MyRecordID = MyRecordID UID
-- constructor which can take any integral type because I get
-- Int32 from the database and it's a lot of annoying
-- boilerplate each time
myRecordID :: Integral a => a -> MyRecordID
myRecordID = MyRecordID . fromInteger
有一些这样的记录,而不是每次手工编写这些构造函数,我认为这可能是使用TH的理想方式。
从这个答案,我设法使newtype
声明(虽然它真的困扰我,有很多我不明白在这):
wrapUID :: String -> Q [Dec]
wrapUID n = (:[]) <$> dataD (cxt [])
name
[]
Nothing
[normalC name
[bangType (bang noSourceUnpackedness noSourceStrictness)
[t| UID |]]]
[]
where name = mkName n
我不知道如何创建"构造器"声明。
如果您满足于重用现有的解决方案而不是编写自己的解决方案,您可以使用product-profunctors
。
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Profunctor.Product.TH
import Data.Profunctor.Product.Newtype
type UID = Integer
newtype MyRecordID' a = MyRecordID a
type MyRecordID = MyRecordID' UID
$(makeAdaptorAndInstanceInferrable "pMyRecordID" ''MyRecordID')
myAnything :: (Newtype t, Integral a) => a -> t a
myAnything = constructor . fromIntegral