{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Generics.Product.Internal.HList
( GIsList(..)
, IndexList (..)
, HList (..)
, type (++)
, Elem
, ListTuple (..)
, TupleToList
) where
import GHC.TypeLits
import Data.Kind (Type)
import GHC.Generics
import Data.Profunctor.Indexed
import Data.Generics.Internal.Profunctor.Lens
import Data.Generics.Internal.Profunctor.Iso
data HList (as :: [Type]) where
Nil :: HList '[]
(:>) :: a -> HList as -> HList (a ': as)
infixr 5 :>
type family ((as :: [k]) ++ (bs :: [k])) :: [k] where
'[] ++ bs = bs
(a ': as) ++ bs = a ': as ++ bs
instance Semigroup (HList '[]) where
_ <> _ = Nil
instance Monoid (HList '[]) where
mempty = Nil
mappend _ _ = Nil
instance (Semigroup a, Semigroup (HList as)) => Semigroup (HList (a ': as)) where
(x :> xs) <> (y :> ys) = (x <> y) :> (xs <> ys)
instance (Monoid a, Monoid (HList as)) => Monoid (HList (a ': as)) where
mempty = mempty :> mempty
mappend (x :> xs) (y :> ys) = mappend x y :> mappend xs ys
class Elem (as :: [(k, Type)]) (key :: k) (i :: Nat) a | as key -> i a
instance {-# OVERLAPPING #-} pos ~ 0 => Elem (a ': xs) key pos a
instance (Elem xs key i a, pos ~ (i + 1)) => Elem (x ': xs) key pos a
class GIsList
(f :: Type -> Type)
(g :: Type -> Type)
(as :: [Type])
(bs :: [Type]) | f -> as, g -> bs, bs f -> g, as g -> f where
glist :: Iso (f x) (g x) (HList as) (HList bs)
instance
( GIsList l l' as as'
, GIsList r r' bs bs'
, Appending as bs cs as' bs' cs'
, cs ~ (as ++ bs)
, cs' ~ (as' ++ bs')
) => GIsList (l :*: r) (l' :*: r') cs cs' where
glist = prodIso . pairing glist glist . appending
{-# INLINE glist #-}
instance GIsList f g as bs => GIsList (M1 t meta f) (M1 t meta g) as bs where
glist = mIso . glist
{-# INLINE glist #-}
instance GIsList (Rec0 a) (Rec0 b) '[a] '[b] where
glist = kIso . singleton
{-# INLINE glist #-}
instance GIsList U1 U1 '[] '[] where
glist = iso (const Nil) (const U1)
{-# INLINE glist #-}
class Appending as bs cs as' bs' cs'
| as bs cs cs' -> as' bs'
, as' bs' cs cs' -> as bs
, as bs -> cs
, as' bs' -> cs'
where
appending :: Iso (HList as, HList bs) (HList as', HList bs') (HList cs) (HList cs')
instance Appending '[] bs bs '[] bs' bs' where
appending = iso snd (Nil,)
instance
Appending as bs cs as' bs' cs'
=> Appending (a ': as) bs (a ': cs) (a' ': as') bs' (a' ': cs') where
appending
= pairing (fromIso consing) id
. assoc3
. pairing id appending
. consing
singleton :: Iso a b (HList '[a]) (HList '[ b])
singleton = iso (:> Nil) (\(x :> _) -> x)
consing :: Iso (a, HList as) (b, HList bs) (HList (a ': as)) (HList (b ': bs))
consing = iso (\(x, xs) -> x :> xs) (\(x :> xs) -> (x, xs))
class IndexList (i :: Nat) as bs a b | i as -> a, i bs -> b, i as b -> bs, i bs a -> as where
point :: Lens (HList as) (HList bs) a b
instance {-# OVERLAPPING #-}
( as ~ (a ': as')
, bs ~ (b ': as')
) => IndexList 0 as bs a b where
point = lens (\(x :> xs) -> (xs, x)) (\(xs, x') -> x' :> xs)
{-# INLINE point #-}
instance
( IndexList (n - 1) as' bs' a b
, as ~ (x ': as')
, bs ~ (x ': bs')
) => IndexList n as bs a b where
point = fromIso consing . second' . point @(n-1)
{-# INLINE point #-}
class ListTuple (tuple :: Type) (tuple' :: Type) (as :: [Type]) (bs :: [Type]) | as -> tuple, bs -> tuple' where
tupled :: Iso (HList as) (HList bs) tuple tuple'
tupled = iso (listToTuple @tuple @tuple' @as @bs) (tupleToList @tuple @tuple' @as @bs)
{-# INLINE tupled #-}
tupleToList :: tuple' -> HList bs
listToTuple :: HList as -> tuple
instance ListTuple () () '[] '[]
where
tupleToList _ = Nil
listToTuple _ = ()
instance ListTuple a a' '[a] '[a'] where
tupleToList a
= a :> Nil
listToTuple (a :> Nil)
= a
instance ListTuple
(a1, b1) (a2, b2)
[a1, b1] [a2, b2]
where
tupleToList (a, b)
= a :> b :> Nil
listToTuple (a :> b :> Nil)
= (a, b)
instance ListTuple
(a1, b1, c1) (a2, b2, c2)
[a1, b1, c1] [a2, b2, c2]
where
tupleToList (a, b, c)
= a :> b :> c :> Nil
listToTuple (a :> b :> c :> Nil)
= (a, b, c)
instance ListTuple
(a1, b1, c1, d1) (a2, b2, c2, d2)
[a1, b1, c1, d1] [a2, b2, c2, d2]
where
tupleToList (a, b, c, d)
= a :> b :> c :> d:> Nil
listToTuple (a :> b :> c :> d :> Nil)
= (a, b, c, d)
instance ListTuple
(a1, b1, c1, d1, e1) (a2, b2, c2, d2, e2)
[a1, b1, c1, d1, e1] [a2, b2, c2, d2, e2]
where
tupleToList (a, b, c, d, e)
= a :> b :> c :> d:> e :> Nil
listToTuple (a :> b :> c :> d :> e :> Nil)
= (a, b, c, d, e)
instance ListTuple
(a1, b1, c1, d1, e1, f1) (a2, b2, c2, d2, e2, f2)
[a1, b1, c1, d1, e1, f1] [a2, b2, c2, d2, e2, f2]
where
tupleToList (a, b, c, d, e, f)
= a :> b :> c :> d:> e :> f :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> Nil)
= (a, b, c, d, e, f)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1) (a2, b2, c2, d2, e2, f2, g2)
[a1, b1, c1, d1, e1, f1, g1] [a2, b2, c2, d2, e2, f2, g2]
where
tupleToList (a, b, c, d, e, f, g)
= a :> b :> c :> d:> e :> f :> g :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> Nil)
= (a, b, c, d, e, f, g)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1) (a2, b2, c2, d2, e2, f2, g2, h2)
[a1, b1, c1, d1, e1, f1, g1, h1] [a2, b2, c2, d2, e2, f2, g2, h2]
where
tupleToList (a, b, c, d, e, f, g, h)
= a :> b :> c :> d:> e :> f :> g :> h :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> Nil)
= (a, b, c, d, e, f, g, h)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1) (a2, b2, c2, d2, e2, f2, g2, h2, j2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1] [a2, b2, c2, d2, e2, f2, g2, h2, j2]
where
tupleToList (a, b, c, d, e, f, g, h, j)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> Nil)
= (a, b, c, d, e, f, g, h, j)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> Nil)
= (a, b, c, d, e, f, g, h, j, k)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n, o)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1, r1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2, r2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1, r1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2, r2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> r :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> r :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r)
instance ListTuple
(a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1) (a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2, r2, s2)
[a1, b1, c1, d1, e1, f1, g1, h1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1] [a2, b2, c2, d2, e2, f2, g2, h2, j2, k2, l2, m2, n2, o2, p2, q2, r2, s2]
where
tupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r, s)
= a :> b :> c :> d:> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> r :> s :> Nil
listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> j :> k :> l :> m :> n :> o :> p :> q :> r :> s :> Nil)
= (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r, s)
type family TupleToList a where
TupleToList () = '[]
TupleToList (a, b) = '[a, b]
TupleToList (a, b, c) = '[a, b, c]
TupleToList (a, b, c, d) = '[a, b, c, d]
TupleToList (a, b, c, d, e) = '[a, b, c, d, e]
TupleToList (a, b, c, d, e, f) = '[a, b, c, d, e, f]
TupleToList (a, b, c, d, e, f, g) = '[a, b, c, d, e, f, g]
TupleToList (a, b, c, d, e, f, g, h) = '[a, b, c, d, e, f, g, h]
TupleToList (a, b, c, d, e, f, g, h, j) = '[a, b, c, d, e, f, g, h, j]
TupleToList (a, b, c, d, e, f, g, h, j, k) = '[a, b, c, d, e, f, g, h, j, k]
TupleToList (a, b, c, d, e, f, g, h, j, k, l) = '[a, b, c, d, e, f, g, h, j, k, l]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m) = '[a, b, c, d, e, f, g, h, j, k, l, m]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n) = '[a, b, c, d, e, f, g, h, j, k, l, m, n]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o) = '[a, b, c, d, e, f, g, h, j, k, l, m, n, o]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p) = '[a, b, c, d, e, f, g, h, j, k, l, m, n, o, p]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q) = '[a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r) = '[a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r]
TupleToList (a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r, s) = '[a, b, c, d, e, f, g, h, j, k, l, m, n, o, p, q, r, s]
TupleToList a = '[a]