@@ -0,0 +1,336 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE FunctionalDependencies #-}
7+{-# LANGUAGE GADTs #-}
8+{-# LANGUAGE PatternSynonyms #-}
9+{-# LANGUAGE PolyKinds #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeApplications #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+{-# OPTIONS_GHC -Wno-incomplete-patterns -Wno-redundant-constraints #-}
17+
18+module Control.Tuple.Morph
19+ ( morphTuples,
20+ morphReorderTuples,
21+ morphPickTuples,
22+ TupleMorphable,
23+ CheckListsForTupleIso,
24+ ReorderList,
25+ )
26+where
27+
28+import Data.Kind
29+import Data.Proxy
30+import GHC.Generics
31+import GHC.TypeLits hiding (Nat)
32+
33+morphTuples :: (TupleMorphable a c, TupleMorphable b c) => a -> b
34+morphTuples = morph . unmorph
35+
36+morphPickTuples ::
37+ ( TupleMorphable a b,
38+ TupleMorphable c d,
39+ ReorderList b d
40+ ) =>
41+ a ->
42+ c
43+morphPickTuples = morph . hReorder Proxy . unmorph
44+
45+type CheckListsForTupleIso b d =
46+ EqOrError (Length b) (Length d)
47+ ( 'Text "Not isomorphic tuple contents:"
48+ ':$$: 'Text " " ':<>: 'ShowType b
49+ ':$$: 'Text " " ':<>: 'ShowType d
50+ )
51+
52+morphReorderTuples ::
53+ ( TupleMorphable a b,
54+ TupleMorphable c d,
55+ ReorderList b d,
56+ CheckListsForTupleIso b d
57+ ) =>
58+ a ->
59+ c
60+morphReorderTuples = morph . hReorder Proxy . unmorph
61+
62+type family EqOrError a b e :: Constraint where
63+ EqOrError a a _ = a ~ a
64+ EqOrError _ _ e = TypeError e
65+
66+-- # Nat
67+
68+data Nat where
69+ S :: Nat -> Nat
70+ Z :: Nat
71+
72+-- # HList
73+
74+data HList (ts :: [*]) where
75+ HCons :: t -> HList tt -> HList (t ': tt)
76+ HNil :: HList '[]
77+
78+infixr 5 :+
79+
80+pattern (:+) :: (ts ~ (t : tt)) => t -> HList tt -> HList ts
81+pattern (:+) a b = HCons a b
82+
83+-- ## Taking
84+
85+class TakeableList (n :: Nat) aa bb | n aa -> bb where
86+ hTake :: Proxy n -> HList aa -> HList bb
87+
88+instance TakeableList 'Z a '[] where
89+ hTake _ _ = HNil
90+
91+instance
92+ (TakeableList n aa bb', bb ~ (a ': bb')) =>
93+ TakeableList ('S n) (a ': aa) bb
94+ where
95+ hTake (Proxy :: Proxy ('S n)) (a :+ aa) = a :+ hTake @n Proxy aa
96+
97+-- ## Dropping
98+
99+class DroppableList (n :: Nat) (aa :: [*]) (bb :: [*]) | n aa -> bb where
100+ hDrop :: Proxy n -> HList aa -> HList bb
101+
102+instance DroppableList 'Z aa aa where
103+ hDrop _ aa = aa
104+
105+instance (DroppableList n aa bb) => DroppableList ('S n) (a ': aa) bb where
106+ hDrop (Proxy :: Proxy ('S n)) (_ :+ aa) = hDrop @n Proxy aa
107+
108+-- ## Appending
109+
110+infixr 4 ++:
111+
112+class AppendableList aa bb cc | aa bb -> cc where
113+ (++:) :: HList aa -> HList bb -> HList (aa ++ bb)
114+
115+instance AppendableList '[] bb bb where
116+ HNil ++: bb = bb
117+
118+instance
119+ ( AppendableList aa bb cc,
120+ cc ~ (aa ++ bb),
121+ ((a ': aa) ++ bb) ~ (a ': cc)
122+ ) =>
123+ AppendableList (a ': aa) bb (a ': cc)
124+ where
125+ (a :+ aa) ++: bb = a :+ (aa ++: bb)
126+
127+-- ## Finding
128+
129+class FindableList ts t where
130+ hFind :: HList ts -> t
131+
132+instance
133+ {-# OVERLAPPING #-}
134+ (NotFindableList ts t) =>
135+ FindableList (t ': ts) t
136+ where
137+ hFind (t :+ _) = t
138+
139+instance
140+ (TEq a t ~ 'False, FindableList ts a) =>
141+ FindableList (t ': ts) a
142+ where
143+ hFind (_ :+ ts) = hFind ts
144+
145+instance
146+ ( TypeError
147+ ('Text "Could not find type " ':<>: 'ShowType a ':<>: 'Text " in tuple.")
148+ ) =>
149+ FindableList '[] a
150+ where
151+ hFind = error "oh no"
152+
153+class NotFindableList ts t
154+
155+instance
156+ {-# OVERLAPPING #-}
157+ ( TypeError
158+ ('Text "Type " ':<>: 'ShowType t ':<>: 'Text " is not unique in tuple.")
159+ ) =>
160+ NotFindableList (t ': ts) t
161+
162+instance (NotFindableList ts a) => NotFindableList (t ': ts) a
163+
164+instance NotFindableList '[] a
165+
166+class ReorderList as bs where
167+ hReorder :: Proxy bs -> HList as -> HList bs
168+
169+instance (FindableList as b, ReorderList as bs) => ReorderList as (b ': bs) where
170+ hReorder _ as = hFind as :+ hReorder (Proxy @bs) as
171+
172+instance ReorderList as '[] where
173+ hReorder _ _ = HNil
174+
175+type family TEq a b :: Bool where
176+ TEq a a = 'True
177+ TEq a b = 'False
178+
179+-- ## Other
180+
181+type family (++) (as :: [k]) (bs :: [k]) :: [k] where
182+ (++) '[] b = b
183+ (++) (a ': as) bs = a ': (as ++ bs)
184+
185+type family Length (aa :: [k]) :: Nat where
186+ Length '[] = 'Z
187+ Length (a ': aa) = 'S (Length aa)
188+
189+-- # Morphing
190+
191+class TupleMorphable t th | t -> th where
192+
193+ unmorph :: t -> HList th
194+
195+ morph :: HList th -> t
196+
197+instance (IsMophableTuple t ~ flag, TupleMorphable' t th flag) => TupleMorphable t th where
198+
199+ unmorph = unmorph' (Proxy @flag)
200+
201+ morph = morph' (Proxy @flag)
202+
203+-- ## Implementation
204+
205+class TupleMorphable' t th (flag :: Bool) | t flag -> th where
206+
207+ unmorph' :: Proxy flag -> t -> HList th
208+
209+ morph' :: Proxy flag -> HList th -> t
210+
211+instance TupleMorphable' t '[t] 'False where
212+
213+ unmorph' _ t = t :+ HNil
214+
215+ morph' _ (t :+ HNil) = t
216+
217+instance (GenericTupleMorphable (Rep t) th, Generic t) => TupleMorphable' t th 'True where
218+
219+ unmorph' _ = genericUnmorph . from
220+
221+ morph' _ = to . genericMorph
222+
223+-- ### Generics
224+
225+class GenericTupleMorphable f th | f -> th where
226+
227+ genericUnmorph :: f p -> HList th
228+
229+ genericMorph :: HList th -> f p
230+
231+instance (GenericTupleMorphable f t) => GenericTupleMorphable (M1 i c f) t where
232+
233+ genericUnmorph = genericUnmorph . unM1
234+
235+ genericMorph = M1 . genericMorph
236+
237+instance (TupleMorphable c t) => GenericTupleMorphable (K1 i c) t where
238+
239+ genericUnmorph = unmorph . unK1
240+
241+ genericMorph = K1 . morph
242+
243+instance GenericTupleMorphable U1 '[] where
244+
245+ genericUnmorph _ = HNil
246+
247+ genericMorph _ = U1
248+
249+type CanTakeDrop a b c =
250+ ( TakeableList (Length a) c a,
251+ DroppableList (Length a) c b,
252+ c ~ (a ++ b)
253+ )
254+
255+instance
256+ ( GenericTupleMorphable f a,
257+ GenericTupleMorphable g b,
258+ AppendableList a b c,
259+ CanTakeDrop a b c
260+ ) =>
261+ GenericTupleMorphable (f :*: g) c
262+ where
263+
264+ genericUnmorph (a :*: b) = genericUnmorph a ++: genericUnmorph b
265+
266+ genericMorph cc = genericMorph aa :*: genericMorph bb
267+ where
268+ aa = hTake @(Length a) Proxy cc
269+ bb = hDrop @(Length a) Proxy cc
270+
271+-- ## Other
272+
273+type family IsMophableTuple t :: Bool where
274+ IsMophableTuple () = 'True
275+ IsMophableTuple (a, b) = 'True
276+ IsMophableTuple (a, b, c) = 'True
277+ IsMophableTuple (a, b, c, d) = 'True
278+ IsMophableTuple (a, b, c, d, e) = 'True
279+ IsMophableTuple (a, b, c, d, e, f) = 'True
280+ IsMophableTuple (a, b, c, d, e, f, g) = 'True
281+ IsMophableTuple (a, b, c, d, e, f, g, h) = 'True
282+ IsMophableTuple (a, b, c, d, e, f, g, h, i) = 'True
283+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j) = 'True
284+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k) = 'True
285+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l) = 'True
286+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m) = 'True
287+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = 'True
288+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = 'True
289+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = 'True
290+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) = 'True
291+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) = 'True
292+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) = 'True
293+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) = 'True
294+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) = 'True
295+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) = 'True
296+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) = 'True
297+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) = 'True
298+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y) = 'True
299+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) = 'True
300+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1) = 'True
301+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1) = 'True
302+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1) = 'True
303+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1) = 'True
304+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1) = 'True
305+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1) = 'True
306+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1) = 'True
307+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1) = 'True
308+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1) = 'True
309+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1) = 'True
310+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1) = 'True
311+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1) = 'True
312+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1) = 'True
313+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1) = 'True
314+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1) = 'True
315+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1) = 'True
316+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1) = 'True
317+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1) = 'True
318+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1) = 'True
319+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1) = 'True
320+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1) = 'True
321+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1) = 'True
322+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1) = 'True
323+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1) = 'True
324+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1) = 'True
325+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1) = 'True
326+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2) = 'True
327+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2) = 'True
328+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2) = 'True
329+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2) = 'True
330+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2) = 'True
331+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2, f2) = 'True
332+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2) = 'True
333+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2) = 'True
334+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2) = 'True
335+ IsMophableTuple (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2, j2) = 'True
336+ IsMophableTuple c = 'False