module FP.Pretty.Deriving where import FP.Prelude import FP.Pretty.Pretty import Language.Haskell.TH import qualified Data.Text as Text -- makePrettySumLogic [C₁,…,Cₙ] ty [a₁,…,aₙ] [(con₁,[conty₁₁,…,conty₁⸤n₁⸥]),…,(conₘ,[contyₘ₁,…,contyₘ⸤nₘ⸥])] ≔ -- [| instance -- (C₁,…,Cₙ -- ,Pretty conty₁₁,…,Pretty conty₁⸤n₁⸥,…,Pretty contyₘ₁,…,Pretty contyₘ⸤nₘ⸥ -- ) ⇒ Pretty (ty a₁ … aₙ) where -- pretty (con₁ (x₁₁ ∷ conty₁₁) … x₁⸤n₁⸥) = app [con "con₁",pretty x₁₁,…,pretty x₁⸤n₁⸥] -- … -- pretty (conₘ (xₘ₁ ∷ contyₘ₁) … xₘ⸤nₘ⸥) = app [con "conₘ",pretty xₘ₁,…,pretty xₘ⸤nₘ⸥] -- |] makePrettySumLogic ∷ (Monad m,MonadQ m) ⇒ Cxt → Name → [TyVarBndr] → [(Name,[Type])] → m [Dec] makePrettySumLogic cx ty tyargs concontys = qio $ do conxs ∷ [(Name,[Name])] ← mapMOn concontys $ \ (con,contys) → do tmpˣˢ ← mapMOn contys $ const $ newName $ chars "x" return (con,tmpˣˢ) let tyargVars = map (VarT ∘ thTyVarBndrName) tyargs instanceCx ∷ [Pred] instanceCx = list $ uniques $ concat [cx,map (\ x → ConT ''Pretty ◇⋅ x) $ concat $ map snd concontys] instanceTy ∷ Type instanceTy = ConT ''Pretty ◇⋅ (ConT ty ◇⋅| tyargVars) instanceDec ∷ Dec instanceDec = FunD 'pretty $ mapOn conxs $ \ (con,tmpˣˢ) → let conString = thString $ 𝕤 $ nameBase con prettyCon = VarE 'ppCon ◇⋅ conString prettyXs = mapOn tmpˣˢ $ \ x → VarE 'pretty ◇⋅ VarE x in thSingleClause [ConP con $ map VarP tmpˣˢ] $ VarE 'ppApp ◇⋅ prettyCon ◇⋅ ListE prettyXs return $ single $ InstanceD instanceCx instanceTy $ single instanceDec makePrettySum ∷ Name → Q [Dec] makePrettySum name = do (cx,ty,tyargs,cs,_) ← returnMaybe abortIO ∘ (thViewADT *∘ view thTyConIL) *$ reify name scs ← mapM (returnMaybe abortIO ∘ thViewSimpleCon) cs makePrettySumLogic cx ty tyargs scs -- makePrettyUnionLogic [C₁,…,Cₙ] ty [a₁,…,aₙ] [(con₁,[conty₁₁,…,conty₁⸤n₁⸥]),…,(conₘ,[contyₘ₁,…,contyₘ⸤nₘ⸥])] ≔ -- [| instance -- (C₁,…,Cₙ -- ,Pretty conty₁₁,…,Pretty conty₁⸤n₁⸥,…,Pretty contyₘ₁,…,Pretty contyₘ⸤nₘ⸥ -- ) ⇒ Pretty (ty a₁ … aₙ) where -- pretty (con₁ (x₁₁ ∷ conty₁₁) … x₁⸤n₁⸥) = tup [pretty x₁₁,…,pretty x₁⸤n₁⸥] -- … -- pretty (conₘ (xₘ₁ ∷ contyₘ₁) … xₘ⸤nₘ⸥) = tup [pretty xₘ₁,…,pretty xₘ⸤nₘ⸥] -- |] makePrettyUnionLogic ∷ (Monad m,MonadQ m) ⇒ Cxt → Name → [TyVarBndr] → [(Name,[Type])] → m [Dec] makePrettyUnionLogic cx ty tyargs concontys = qio $ do conxs ∷ [(Name,[Name])] ← mapMOn concontys $ \ (con,fieldtys) → do tmpˣˢ ← mapMOn fieldtys $ const $ newName $ chars "x" return (con,tmpˣˢ) let tyargVars = map (VarT ∘ thTyVarBndrName) tyargs instanceCx ∷ [Pred] instanceCx = list $ uniques $ concat [cx,map (\ x → ConT ''Pretty ◇⋅ x) $ concat $ map snd concontys] instanceTy ∷ Type instanceTy = ConT ''Pretty ◇⋅ (ConT ty ◇⋅| tyargVars) instanceDec ∷ Dec instanceDec = FunD 'pretty $ mapOn conxs $ \ (con,tmpˣˢ) → thSingleClause [ConP con $ map VarP tmpˣˢ] $ case tmpˣˢ of [] → VarE 'pretty ◇⋅ ConE '() [x] → VarE 'pretty ◇⋅ VarE x _ → let prettyXs = mapOn tmpˣˢ $ \ x → VarE 'pretty ◇⋅ VarE x in VarE 'ppCollection ◇⋅ thString "⟨" ◇⋅ thString "⟩" ◇⋅ thString "," ◇⋅ ListE prettyXs return $ single $ InstanceD instanceCx instanceTy $ single $ instanceDec makePrettyUnion ∷ Name → Q [Dec] makePrettyUnion name = do (cx,ty,tyargs,cs,_) ← returnMaybe abortIO ∘ (thViewADT *∘ view thTyConIL) *$ reify name scs ← mapM (returnMaybe abortIO ∘ thViewSimpleCon) cs makePrettyUnionLogic cx ty tyargs scs -- makePrettyRecordLogic [C₁,…,Cₙ] ty [a₁,…,aₙ] con [(field₁,fieldty₁),…,(fieldₙ,fieldtyₙ)] ≔ -- [| instance -- (C₁,…,Cₙ -- ,Pretty fieldty₁,…,Pretty fieldtyₙ -- ) ⇒ Pretty (ty a₁ … aₙ) where -- pretty (con {field₁ = tmp₁;fieldₙ = tmpₙ}) = app [con "con",record [("field₁",tmp₁),…,("fieldₙ",tmpₙ) -- |] makePrettyRecordLogic ∷ (Monad m,MonadQ m) ⇒ Cxt → Name → [TyVarBndr] → Name → [(Name,Type)] → m [Dec] makePrettyRecordLogic cx ty tyargs con fieldfieldtys = qio $ do let conPrefix = 𝕤 $ mapHead lowerChar $ nameBase con fieldNameTmps ← mapMOn fieldfieldtys $ \ (field,_) → do let (_prefix,afterPrefix) = Text.breakOnEnd conPrefix $ 𝕤 $ nameBase field loweredAfterPrefix = 𝕤 $ mapHead lowerChar $ list afterPrefix tmpˣ ← newName $ chars "x" return (field,loweredAfterPrefix,tmpˣ) let tyargVars = map (VarT ∘ thTyVarBndrName) tyargs instanceCx ∷ [Pred] instanceCx = list $ uniques $ concat [cx,map (\ x → ConT ''Pretty ◇⋅ x) $ map snd fieldfieldtys] instanceTy ∷ Type instanceTy = ConT ''Pretty ◇⋅ (ConT ty ◇⋅| tyargVars) instanceDec ∷ Dec instanceDec = FunD 'pretty $ single $ thSingleClause [RecP con $ mapOn fieldNameTmps $ \ (field,_name,tmpˣ) → (field,VarP tmpˣ)] $ VarE 'ppApp ◇⋅ (VarE 'ppCon ◇⋅ (thString $ 𝕤 $ nameBase con)) ◇$ ListE $ single $ VarE 'ppRecord ◇⋅ thString "≔" ◇$ ListE $ mapOn fieldNameTmps $ \ (_field,name,tmpˣ) → tup [ VarE 'ppText ◇⋅ (thString name) , VarE 'pretty ◇⋅ VarE tmpˣ ] return $ single $ InstanceD instanceCx instanceTy $ single $ instanceDec makePrettyRecord ∷ Name → Q [Dec] makePrettyRecord name = do (cx,ty,tyargs,c,_) ← returnMaybe abortIO ∘ (thViewSingleConADT *∘ view thTyConIL) *$ reify name (con,fields) ← returnMaybe abortIO $ view thRecCL c let fieldfieldtys = mapOn fields $ \ (field,_,fieldty) → (field,fieldty) makePrettyRecordLogic cx ty tyargs con fieldfieldtys