domain-optics-0.1.0.3: library/DomainOptics/Util/OpticsTH.hs
-- |
-- TH utils for optics.
module DomainOptics.Util.OpticsTH where
import qualified Data.Text as Text
import DomainOptics.Prelude
import Language.Haskell.TH
import qualified Optics.Core as Optics
import THLego.Helpers
import qualified THLego.Lambdas as Lambdas
import qualified TemplateHaskell.Compat.V0208 as Compat
-- * Optics
productLensVlE :: Name -> Int -> Int -> Exp
productLensVlE conName numMembers index =
AppE (VarE 'Optics.lensVL) (Lambdas.vlLens conName numMembers index)
productLensE :: Name -> Int -> Int -> Exp
productLensE conName numMembers index =
AppE (AppE (VarE 'Optics.lens) getterE) setterE
where
getterE =
Lambdas.productGetter conName numMembers index
setterE =
Lambdas.productSetter conName numMembers index
-- |
-- >prism' Dog (\ case
-- > Dog a -> Just a
-- > _ -> Nothing)
singleMemberPrismE :: Name -> Exp
singleMemberPrismE conName =
AppE
(AppE (VarE 'Optics.prism') (ConE conName))
( LamE
[VarP aName]
( CaseE
(VarE aName)
[ Match (Compat.conp conName [VarP bName]) (NormalB (AppE (ConE 'Just) (VarE bName))) [],
Match WildP (NormalB (ConE 'Nothing)) []
]
)
)
-- |
-- Prism to a tuple of members.
prismE :: Name -> Int -> Exp
prismE conName numMembers =
multiAppE
(VarE 'Optics.prism')
[ Lambdas.tupleOrSingletonToProduct conName numMembers,
Lambdas.adtConstructorNarrower conName numMembers
]
emptyConLensE :: Name -> Exp
emptyConLensE conName =
AppE (AppE (VarE 'Optics.lens) getterE) setterE
where
getterE =
LamE
[VarP aName]
( CaseE
(VarE aName)
[ Match (Compat.conp conName []) (NormalB (ConE 'True)) [],
Match WildP (NormalB (ConE 'False)) []
]
)
setterE =
LamE [VarP aName, VarP bName] (CondE (VarE bName) (ConE conName) (VarE aName))
namedFieldLensE :: Name -> Exp
namedFieldLensE fieldName =
AppE (AppE (VarE 'Optics.lens) getterE) setterE
where
getterE =
VarE fieldName
setterE =
Lambdas.namedFieldSetter fieldName
-- * LabelOptic instances
-- |
-- General definition helper.
labelOpticInstanceD :: TyLit -> Name -> Name -> Type -> Exp -> Dec
labelOpticInstanceD lit opticType typeName aAndBType exp =
InstanceD Nothing cxt headType [labelOpticDec]
where
cxt =
[aPred, bPred, cPred]
where
aPred =
eqConstraintT aName aAndBType
bPred =
eqConstraintT bName aAndBType
cPred =
eqConstraintT cName (ConT opticType)
headType =
foldl'
AppT
(ConT ''Optics.LabelOptic)
[ LitT lit,
VarT cName,
ConT typeName,
ConT typeName,
VarT aName,
VarT bName
]
labelOpticDec =
FunD 'Optics.labelOptic [Clause [] (NormalB exp) []]
-- |
-- >instance (k ~ A_Lens, a ~ String, b ~ String) => LabelOptic "name" k Human Human a b where
-- > labelOptic = lensVL $ \f s -> (\v -> s { humanName = v }) <$> f (humanName s)
fieldLensLabelOpticInstanceDec :: TyLit -> Name -> Type -> Int -> Int -> Dec
fieldLensLabelOpticInstanceDec lit typeName aAndBType numMembers index =
labelOpticInstanceD
lit
''Optics.A_Lens
typeName
aAndBType
(productLensVlE typeName numMembers index)
-- |
-- >instance (k ~ A_Prism, a ~ String, b ~ String) => LabelOptic "dog" k Pet Pet a b where
-- > labelOptic =
-- > prism' Dog (\ case
-- > Dog a -> Just a
-- > _ -> Nothing)
prismLabelOpticInstanceDec :: TyLit -> Name -> Name -> [Type] -> Dec
prismLabelOpticInstanceDec lit typeName conName memberTypes =
labelOpticInstanceD lit ''Optics.A_Prism typeName aAndBType exp
where
aAndBType =
appliedTupleOrSingletonT memberTypes
exp =
prismE conName (length memberTypes)
emptyConLensLabelOpticInstanceDec :: TyLit -> Name -> Name -> Dec
emptyConLensLabelOpticInstanceDec lit typeName conName =
labelOpticInstanceD lit ''Optics.A_Lens typeName aAndBType exp
where
aAndBType =
ConT ''Bool
exp =
emptyConLensE conName