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)
62 | classTy ≡ ''SortingCollection
63 = return (wrapperTy, deriveSortingCollection)
64 inspectInstance (AppT (AppT (AppT (ConT classTy) wrapperTy) _) _)
66 = return (wrapperTy, deriveIndexed)
68 = return (wrapperTy, deriveMap)
70 = fail $ "deriveInstance: unsupported type: " ⧺ pprint ty
72 genWrap ∷ Type → Q (Exp, [Dec])
74 = do name ← newName "wrap"
75 (con, ty) ← wrapperConTy wrapperTy
77 [ sigD name [t| $(return ty) → $(return wrapperTy) |]
78 , pragInlD name (inlineSpecNoPhase True True)
79 , funD name [clause [] (normalB (conE con)) []]
81 return (VarE name, decls)
83 genUnwrap ∷ Type → Q (Exp, [Dec])
85 = do name ← newName "unwrap"
87 (con, ty) ← wrapperConTy wrapperTy
89 [ sigD name [t| $(return wrapperTy) → $(return ty) |]
90 , pragInlD name (inlineSpecNoPhase True True)
91 , funD name [clause [conP con [varP i]] (normalB (varE i)) []]
93 return (VarE name, decls)
95 wrapperConTy ∷ Type → Q (Name, Type)
96 wrapperConTy = (conTy =≪) ∘ tyInfo
98 tyInfo ∷ Type → Q Info
99 tyInfo (ConT name) = reify name
100 tyInfo (AppT ty _) = tyInfo ty
101 tyInfo (SigT ty _) = tyInfo ty
103 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint ty
105 conTy ∷ Info → Q (Name, Type)
106 conTy (TyConI (NewtypeD [] _ [] (NormalC con [(NotStrict, ty)]) []))
109 = fail $ "wrapperConTy: unsupported type: " ⧺ pprint info
111 methodNames ∷ Name → Q [Name]
112 methodNames = (names =≪) ∘ reify
114 names ∷ Info → Q [Name]
115 names (ClassI (ClassD _ _ _ _ decls) _)
116 = return ∘ catMaybes $ map name decls
117 names c = fail $ "methodNames: not a class: " ⧺ pprint c
119 name ∷ Dec → Maybe Name
120 name (SigD n _) = Just n
123 pointfreeMethod ∷ (Name → Q Exp) → Name → [Q Dec]
124 pointfreeMethod f name
125 = [ funD name [clause [] (normalB (f name)) []]
126 -- THINKME: Inserting PragmaD in an InstanceD causes an error
127 -- least GHC 7.0.3. Why?
128 -- , pragInlD name (inlineSpecNoPhase True False)
131 deriveUnfoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
132 deriveUnfoldable c ty wrap unwrap
133 = do names ← methodNames ''Unfoldable
134 instanceD c ty $ concatMap (pointfreeMethod exp) names
139 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insert |]
143 = [| $wrap ∘ singleton |]
145 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertMany |]
146 | name ≡ 'insertManySorted
147 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ insertManySorted |]
149 = fail $ "deriveUnfoldable: unknown method: " ⧺ pprint name
151 deriveFoldable ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
152 deriveFoldable c ty _ unwrap
153 = do names ← methodNames ''Foldable
154 instanceD c ty $ concatMap (pointfreeMethod exp) names
159 = [| fold ∘ $unwrap |]
161 = [| (∘ $unwrap) ∘ foldMap |]
163 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldr |]
165 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ foldl |]
167 = [| (∘ $unwrap) ∘ foldr1 |]
169 = [| (∘ $unwrap) ∘ foldl1 |]
171 = [| null ∘ $unwrap |]
173 = [| size ∘ $unwrap |]
174 | name ≡ 'isSingleton
175 = [| isSingleton ∘ $unwrap |]
177 = fail $ "deriveFoldable: unknown method: " ⧺ pprint name
179 deriveCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
180 deriveCollection c ty wrap unwrap
181 = do names ← methodNames ''Collection
182 instanceD c ty $ concatMap (pointfreeMethod exp) names
187 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ filter |]
189 = fail $ "deriveCollection: unknown method: " ⧺ pprint name
191 deriveIndexed ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
192 deriveIndexed c ty wrap unwrap
193 = do names ← methodNames ''Indexed
194 instanceD c ty $ concatMap (pointfreeMethod exp) names
199 = [| (∘ $unwrap) ∘ index |]
201 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ adjust |]
203 = [| (∘ $unwrap) ∘ inDomain |]
205 = [| ($wrap ∘) ∘ (//) ∘ $unwrap |]
207 = [| (($wrap ∘) ∘) ∘ (∘ $unwrap) ∘ accum |]
209 = fail $ "deriveIndexed: unknown method: " ⧺ pprint name
211 deriveMap ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
212 deriveMap c ty wrap unwrap
213 = do names ← methodNames ''Map
214 instanceD c ty $ concatMap (pointfreeMethod exp) names
219 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ delete |]
221 = [| (∘ $unwrap) ∘ member |]
223 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ union ∘ $unwrap |]
224 | name ≡ 'intersection
225 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ intersection ∘ $unwrap |]
227 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ difference ∘ $unwrap |]
229 = [| (∘ $unwrap) ∘ isSubset ∘ $unwrap |]
230 | name ≡ 'isProperSubset
231 = [| (∘ $unwrap) ∘ isProperSubset ∘ $unwrap |]
233 = [| (∘ $unwrap) ∘ lookup |]
235 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ alter |]
237 = [| ((($wrap ∘) ∘) ∘) ∘ flip flip $unwrap ∘ ((flip ∘ ((∘) ∘)) ∘) ∘ insertWith |]
238 | name ≡ 'fromFoldableWith
239 = [| ($wrap ∘) ∘ fromFoldableWith |]
241 = [| (($wrap ∘) ∘) ∘ foldGroups |]
243 = [| ($wrap ∘) ∘ (∘ $unwrap) ∘ mapWithKey |]
245 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ unionWith |]
246 | name ≡ 'intersectionWith
247 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ intersectionWith |]
248 | name ≡ 'differenceWith
249 = [| (($wrap ∘) ∘) ∘ flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ differenceWith |]
251 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ isSubmapBy |]
252 | name ≡ 'isProperSubmapBy
253 = [| flip flip $unwrap ∘ ((∘) ∘) ∘ (∘ $unwrap) ∘ isProperSubmapBy |]
255 = fail $ "deriveMap: unknown method: " ⧺ pprint name
257 deriveSortingCollection ∷ Q Cxt → Q Type → Q Exp → Q Exp → Q Dec
258 deriveSortingCollection c ty wrap unwrap
259 = do names ← methodNames ''SortingCollection
260 instanceD c ty $ concatMap (pointfreeMethod exp) names
265 = [| (second $wrap <$>) ∘ minView ∘ $unwrap |]
267 = fail $ "deriveSortingCollection: unknown method: " ⧺ pprint name