6 module Data.Collections.Newtype.TH
10 import Control.Applicative hiding (empty)
12 import Control.Monad.Unicode
13 import Data.Collections
14 import Data.Collections.BaseInstances ()
16 import Data.Generics.Aliases
17 import Data.Generics.Schemes
19 import Language.Haskell.TH.Lib
20 import Language.Haskell.TH.Ppr
21 import Language.Haskell.TH.Syntax
22 import Prelude hiding ( concat, concatMap, exp, filter
23 , foldl, foldr, foldl1, foldr1, null)
24 import Prelude.Unicode
26 type Deriver = Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
29 derive ∷ Q [Dec] → Q [Dec]
30 derive = (concat <$>) ∘ (mapM go =≪)
33 go (InstanceD c ty _) = deriveInstance c ty
34 go _ = fail "derive: usage: derive [d| instance A; instance B; ... |]"
36 deriveInstance ∷ Cxt → Type → Q [Dec]
38 = do (wrapperTy, deriver) ← inspectInstance ty
39 (wrap , wrapD ) ← genWrap wrapperTy
40 (unwrap , unwrapD) ← genUnwrap wrapperTy
41 instanceDecl ← deriver (return c )
45 return $ [ d | d ← wrapD , wrap `isUsedIn` instanceDecl ]
46 ⧺ [ d | d ← unwrapD, unwrap `isUsedIn` instanceDecl ]
49 isUsedIn ∷ (Eq α, Typeable α, Data β) ⇒ α → β → Bool
50 isUsedIn α = (> 0) ∘ gcount (mkQ False (≡ α))
52 inspectInstance ∷ Type → Q (Type, Deriver)
53 inspectInstance (AppT (AppT (ConT classTy) wrapperTy) _)
54 | classTy ≡ ''Unfoldable
55 = return (wrapperTy, deriveUnfoldable)
56 | classTy ≡ ''Foldable
57 = return (wrapperTy, deriveFoldable)
58 | classTy ≡ ''Collection
59 = return (wrapperTy, deriveCollection)
60 | classTy ≡ ''SortingCollection
61 = return (wrapperTy, deriveSortingCollection)
62 inspectInstance (AppT (AppT (AppT (ConT classTy) wrapperTy) _) _)
64 = return (wrapperTy, deriveIndexed)
66 = fail $ "deriveInstance: unsupported type: " ⧺ pprint ty
68 genWrap ∷ Type → Q (Exp, [Dec])
70 = do name ← newName "wrap"
71 (con, ty) ← wrapperConTy wrapperTy
73 [ sigD name [t| $(return ty) → $(return wrapperTy) |]
74 , pragInlD name (inlineSpecNoPhase True True)
75 , funD name [clause [] (normalB (conE con)) []]
77 return (VarE name, decls)
79 genUnwrap ∷ Type → Q (Exp, [Dec])
81 = do name ← newName "unwrap"
83 (con, ty) ← wrapperConTy wrapperTy
85 [ sigD name [t| $(return wrapperTy) → $(return ty) |]
86 , pragInlD name (inlineSpecNoPhase True True)
87 , funD name [clause [conP con [varP i]] (normalB (varE i)) []]
89 return (VarE name, decls)
91 wrapperConTy ∷ Type → Q (Name, Type)
92 wrapperConTy = (conTy =≪) ∘ tyInfo
94 tyInfo ∷ Type → Q Info
95 tyInfo (ConT name) = reify name
96 tyInfo (AppT ty _) = tyInfo ty
97 tyInfo (SigT ty _) = tyInfo ty
99 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint ty
101 conTy ∷ Info → Q (Name, Type)
102 conTy (TyConI (NewtypeD [] _ [] (NormalC con [(NotStrict, ty)]) []))
105 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint info
107 methodNames ∷ Name → Q [Name]
108 methodNames = (names =≪) ∘ reify
110 names ∷ Info → Q [Name]
111 names (ClassI (ClassD _ _ _ _ decls) _)
112 = return ∘ catMaybes $ map name decls
113 names c = fail $ "methodNames: not a class: " ⧺ pprint c
115 name ∷ Dec → Maybe Name
116 name (SigD n _) = Just n
119 pointfreeMethod ∷ (Name → Q Exp) → Name → [Q Dec]
120 pointfreeMethod f name
121 = [ funD name [clause [] (normalB (f name)) []]
122 -- THINKME: Inserting PragmaD in an InstanceD causes an error
123 -- least GHC 7.0.3. Why?
124 -- , pragInlD name (inlineSpecNoPhase True False)
127 deriveUnfoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
128 deriveUnfoldable c ty wrap unwrap
129 = do names ← methodNames ''Unfoldable
130 instanceD c ty $ concatMap (pointfreeMethod exp) names
135 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insert |]
139 = [| $wrap ∘ singleton |]
141 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertMany |]
142 | name ≡ 'insertManySorted
143 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertManySorted |]
145 = fail $ "deriveUnfoldable: unknown method: " ⧺ pprint name
147 deriveFoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
148 deriveFoldable c ty _ unwrap
149 = do names ← methodNames ''Foldable
150 instanceD c ty $ concatMap (pointfreeMethod exp) names
155 = [| fold ∘ $unwrap |]
157 = [| (∘ $unwrap) ∘ foldMap |]
159 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldr |]
161 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldl |]
163 = [| (∘ $unwrap) ∘ foldr1 |]
165 = [| (∘ $unwrap) ∘ foldl1 |]
167 = [| null ∘ $unwrap |]
169 = [| size ∘ $unwrap |]
170 | name ≡ 'isSingleton
171 = [| isSingleton ∘ $unwrap |]
173 = fail $ "deriveFoldable: unknown method: " ⧺ pprint name
175 deriveCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
176 deriveCollection c ty wrap unwrap
177 = do names ← methodNames ''Collection
178 instanceD c ty $ concatMap (pointfreeMethod exp) names
183 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ filter |]
185 = fail $ "deriveCollection: unknown method: " ⧺ pprint name
187 deriveIndexed ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
188 deriveIndexed c ty wrap unwrap
189 = do names ← methodNames ''Indexed
190 instanceD c ty $ concatMap (pointfreeMethod exp) names
195 = [| (∘ $unwrap) ∘ index |]
197 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ adjust |]
199 = [| (∘ $unwrap) ∘ inDomain |]
201 = [| ($wrap ∘) ∘ (//) ∘ $unwrap |]
203 = [| (($wrap ∘) ∘) ∘ (∘ $unwrap) ∘ accum |]
205 = fail $ "deriveIndexed: unknown method: " ⧺ pprint name
207 deriveSortingCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
208 deriveSortingCollection c ty wrap unwrap
209 = do names ← methodNames ''SortingCollection
210 instanceD c ty $ concatMap (pointfreeMethod exp) names
215 = [| (second $wrap <$>) ∘ minView ∘ $unwrap |]
217 = fail $ "deriveSortingCollection: unknown method: " ⧺ pprint name