generic-lens-0.3.0.0: src/Data/Generics/Internal/HList.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Generics.Internal.HList
-- Copyright : (C) 2017 Csongor Kiss
-- License : BSD3
-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
-- Stability : experimental
-- Portability : non-portable
--
-----------------------------------------------------------------------------
module Data.Generics.Internal.HList
( (++)
, ListTuple (..)
, GCollectible (..)
) where
import Data.Kind
import GHC.Generics
data HList (xs :: [Type]) where
Nil :: HList '[]
(:>) :: x -> HList xs -> HList (x ': xs)
infixr 5 :>
type family ((as :: [k]) ++ (bs :: [k])) :: [k] where
'[] ++ bs = bs
(a ': as) ++ bs = a ': as ++ bs
append :: HList as -> HList bs -> HList (as ++ bs)
append Nil ys = ys
append (x :> xs) ys = x :> append xs ys
head' :: HList (a ': as) -> a
head' (x :> _) = x
--------------------------------------------------------------------------------
-- * Split HList
class Splittable (as :: [Type]) (bs :: [Type]) (cs :: [Type]) | as bs -> cs, as cs -> bs where
split :: HList cs -> (HList as, HList bs)
instance Splittable '[] bs bs where
split bs = (Nil, bs)
instance Splittable as bs cs => Splittable (a ': as) bs (a ': cs) where
split (a :> as)
= (a :> as', bs)
where (as', bs) = split as
--------------------------------------------------------------------------------
-- * Convert tuples to/from HLists
class ListTuple (tuple :: Type) (as :: [Type]) | as -> tuple where
tupleToList :: tuple -> HList as
listToTuple :: HList as -> tuple
instance ListTuple () '[] where
tupleToList _ = Nil
listToTuple _ = ()
instance ListTuple a '[a] where
tupleToList a
= a :> Nil
listToTuple (a :> Nil)
= a
instance ListTuple (a, b) '[a, b] where
tupleToList (a, b)
= a :> b :> Nil
listToTuple (a :> b :> Nil)
= (a, b)
instance ListTuple (a, b, c) '[a, b, c] where
tupleToList (a, b, c)
= a :> b :> c :> Nil
listToTuple (a :> b :> c :> Nil)
= (a, b, c)
instance ListTuple (a, b, c, d) '[a, b, c, d] where
tupleToList (a, b, c, d)
= a :> b :> c :> d:> Nil
listToTuple (a :> b :> c :> d :> Nil)
= (a, b, c, d)
instance ListTuple (a, b, c, d, e) '[a, b, c, d, e] 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 (a, b, c, d, e, f) '[a, b, c, d, e, f] 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 (a, b, c, d, e, f, g) '[a, b, c, d, e, f, g] 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 (a, b, c, d, e, f, g, h) '[a, b, c, d, e, f, g, h] 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 (a, b, c, d, e, f, g, h, j) '[a, b, c, d, e, f, g, h, j] 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 (a, b, c, d, e, f, g, h, j, k) '[a, b, c, d, e, f, g, h, j, k] 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 (a, b, c, d, e, f, g, h, j, k, l) '[a, b, c, d, e, f, g, h, j, k, l] 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)
--------------------------------------------------------------------------------
class GCollectible (f :: Type -> Type) (as :: [Type]) | f -> as where
gtoCollection :: f x -> HList as
gfromCollection :: HList as -> f x
instance
( GCollectible l as
, GCollectible r bs
, cs ~ (as ++ bs)
, Splittable as bs cs
) => GCollectible (l :*: r) cs where
gtoCollection (l :*: r)
= gtoCollection l `append` gtoCollection r
gfromCollection cs
= gfromCollection as :*: gfromCollection bs
where (as, bs) = split cs
instance GCollectible (K1 R a) '[a] where
gtoCollection = (:> Nil) . unK1
gfromCollection = K1 . head'
instance GCollectible U1 '[] where
gtoCollection U1 = Nil
gfromCollection Nil = U1
instance GCollectible f as => GCollectible (M1 m meta f) as where
gtoCollection = gtoCollection . unM1
gfromCollection = M1 . gfromCollection