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
26 import Prelude.Unicode
28 type Deriver = Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
31 derive ∷ Q [Dec] → Q [Dec]
32 derive = (concat <$>) ∘ (mapM go =≪)
35 go (InstanceD c ty _) = deriveInstance c ty
36 go _ = fail "derive: usage: derive [d| instance A; instance B; ... |]"
38 deriveInstance ∷ Cxt → Type → Q [Dec]
40 = do (wrapperTy, deriver) ← inspectInstance ty
41 (wrap , wrapD ) ← genWrap wrapperTy
42 (unwrap , unwrapD) ← genUnwrap wrapperTy
43 instanceDecl ← deriver (return c )
47 return $ [ d | d ← wrapD , wrap `isUsedIn` instanceDecl ]
48 ⧺ [ d | d ← unwrapD, unwrap `isUsedIn` instanceDecl ]
51 isUsedIn ∷ (Eq α, Typeable α, Data β) ⇒ α → β → Bool
52 isUsedIn α = (> 0) ∘ gcount (mkQ False (≡ α))
54 inspectInstance ∷ Type → Q (Type, Deriver)
55 inspectInstance (AppT (AppT (ConT classTy) wrapperTy) _)
56 | classTy ≡ ''Unfoldable
57 = return (wrapperTy, deriveUnfoldable)
58 | classTy ≡ ''Foldable
59 = return (wrapperTy, deriveFoldable)
60 | classTy ≡ ''Collection
61 = return (wrapperTy, deriveCollection)
63 = return (wrapperTy, deriveSet)
64 | classTy ≡ ''SortingCollection
65 = return (wrapperTy, deriveSortingCollection)
66 inspectInstance (AppT (AppT (AppT (ConT classTy) wrapperTy) _) _)
68 = return (wrapperTy, deriveIndexed)
70 = return (wrapperTy, deriveMap)
72 = fail $ "deriveInstance: unsupported type: " ⧺ pprint ty
74 genWrap ∷ Type → Q (Exp, [Dec])
76 = do name ← newName "wrap"
77 (con, ty) ← wrapperConTy wrapperTy
79 [ sigD name [t| $(return ty) → $(return wrapperTy) |]
80 , pragInlD name (inlineSpecNoPhase True True)
81 , funD name [clause [] (normalB (conE con)) []]
83 return (VarE name, decls)
85 genUnwrap ∷ Type → Q (Exp, [Dec])
87 = do name ← newName "unwrap"
89 (con, ty) ← wrapperConTy wrapperTy
91 [ sigD name [t| $(return wrapperTy) → $(return ty) |]
92 , pragInlD name (inlineSpecNoPhase True True)
93 , funD name [clause [conP con [varP i]] (normalB (varE i)) []]
95 return (VarE name, decls)
97 wrapperConTy ∷ Type → Q (Name, Type)
98 wrapperConTy = (conTy =≪) ∘ tyInfo
100 tyInfo ∷ Type → Q Info
101 tyInfo (ConT name) = reify name
102 tyInfo (AppT ty _) = tyInfo ty
103 tyInfo (SigT ty _) = tyInfo ty
105 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint ty
107 conTy ∷ Info → Q (Name, Type)
108 conTy (TyConI (NewtypeD [] _ [] (NormalC con [(NotStrict, ty)]) []))
111 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint info
113 methodNames ∷ Name → Q [Name]
114 methodNames = (names =≪) ∘ reify
116 names ∷ Info → Q [Name]
117 names (ClassI (ClassD _ _ _ _ decls) _)
118 = return ∘ catMaybes $ map name decls
119 names c = fail $ "methodNames: not a class: " ⧺ pprint c
121 name ∷ Dec → Maybe Name
122 name (SigD n _) = Just n
125 pointfreeMethod ∷ (Name → Q Exp) → Name → [Q Dec]
126 pointfreeMethod f name
127 = [ funD name [clause [] (normalB (f name)) []]
128 -- THINKME: Inserting PragmaD in an InstanceD causes an error
129 -- least GHC 7.0.3. Why?
130 -- , pragInlD name (inlineSpecNoPhase True False)
133 deriveUnfoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
134 deriveUnfoldable c ty wrap unwrap
135 = do names ← methodNames ''Unfoldable
136 instanceD c ty $ concatMap (pointfreeMethod exp) names
141 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insert |]
145 = [| $wrap ∘ singleton |]
147 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertMany |]
148 | name ≡ 'insertManySorted
149 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertManySorted |]
151 = fail $ "deriveUnfoldable: unknown method: " ⧺ pprint name
153 deriveFoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
154 deriveFoldable c ty _ unwrap
155 = do names ← methodNames ''Foldable
156 instanceD c ty $ concatMap (pointfreeMethod exp) names
161 = [| fold ∘ $unwrap |]
163 = [| (∘ $unwrap) ∘ foldMap |]
165 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldr |]
167 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldl |]
169 = [| (∘ $unwrap) ∘ foldr1 |]
171 = [| (∘ $unwrap) ∘ foldl1 |]
173 = [| null ∘ $unwrap |]
175 = [| size ∘ $unwrap |]
176 | name ≡ 'isSingleton
177 = [| isSingleton ∘ $unwrap |]
179 = fail $ "deriveFoldable: unknown method: " ⧺ pprint name
181 deriveCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
182 deriveCollection c ty wrap unwrap
183 = do names ← methodNames ''Collection
184 instanceD c ty $ concatMap (pointfreeMethod exp) names
189 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ filter |]
191 = fail $ "deriveCollection: unknown method: " ⧺ pprint name
193 deriveIndexed ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
194 deriveIndexed c ty wrap unwrap
195 = do names ← methodNames ''Indexed
196 instanceD c ty $ concatMap (pointfreeMethod exp) names
201 = [| (∘ $unwrap) ∘ index |]
203 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ adjust |]
205 = [| (∘ $unwrap) ∘ inDomain |]
207 = [| ($wrap ∘) ∘ (//) ∘ $unwrap |]
209 = [| (($wrap ∘) ∘) ∘ (∘ $unwrap) ∘ accum |]
211 = fail $ "deriveIndexed: unknown method: " ⧺ pprint name
213 deriveMap ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
214 deriveMap c ty wrap unwrap
215 = do names ← methodNames ''Map
216 instanceD c ty $ concatMap (pointfreeMethod exp) names
221 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ delete |]
223 = [| (∘ $unwrap) ∘ member |]
225 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ union ∘ $unwrap |]
226 | name ≡ 'intersection
227 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ intersection ∘ $unwrap |]
229 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ difference ∘ $unwrap |]
231 = [| (∘ $unwrap) ∘ isSubset ∘ $unwrap |]
232 | name ≡ 'isProperSubset
233 = [| (∘ $unwrap) ∘ isProperSubset ∘ $unwrap |]
235 = [| (∘ $unwrap) ∘ lookup |]
237 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ alter |]
239 = [| ((($wrap ∘) ∘) ∘) ∘ flip flip $unwrap ∘ ((flip ∘ ((∘) ∘)) ∘) ∘ insertWith |]
240 | name ≡ 'fromFoldableWith
241 = [| ($wrap ∘) ∘ fromFoldableWith |]
243 = [| (($wrap ∘) ∘) ∘ foldGroups |]
245 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ mapWithKey |]
247 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ unionWith |]
248 | name ≡ 'intersectionWith
249 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ intersectionWith |]
250 | name ≡ 'differenceWith
251 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ differenceWith |]
253 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ isSubmapBy |]
254 | name ≡ 'isProperSubmapBy
255 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ isProperSubmapBy |]
257 = fail $ "deriveMap: unknown method: " ⧺ pprint name
259 deriveSet ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
261 = do names ← methodNames ''Set
262 instanceD c ty $ concatMap (pointfreeMethod exp) names
266 | name ≡ 'haddock_candy
267 = [| haddock_candy |]
269 = fail $ "deriveSet: unknown method: " ⧺ pprint name
271 deriveSortingCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
272 deriveSortingCollection c ty wrap unwrap
273 = do names ← methodNames ''SortingCollection
274 instanceD c ty $ concatMap (pointfreeMethod exp) names
279 = [| (second $wrap <$>) ∘ minView ∘ $unwrap |]
281 = fail $ "deriveSortingCollection: unknown method: " ⧺ pprint name