fir-0.1.0.0: src/Data/Product.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module: Data.Product
This module uses heterogeneous lists to define unbiased products needed by the type-level optics of this library.
-}
module Data.Product where
-- base
import Data.Kind
( Type )
import Data.Type.Equality
( (:~:)(Refl) )
import Unsafe.Coerce
( unsafeCoerce )
-- fir
import Data.Constraint.All
( All )
import Data.Type.List
( KnownLength
, ZipCons
, SameLength
)
import {-# SOURCE #-} FIR.Prim.Types
( PrimTy )
----------------------------------------------------------------------
infixr 3 :>
data HList (as :: [Type]) where
HNil :: HList '[]
(:>) :: a -> HList as -> HList (a ': as)
instance Show (HList '[]) where
show _ = "HNil"
instance ( Show a, Show (HList as) ) => Show (HList (a ': as)) where
show (a :> as) = show a ++ " :> " ++ show as
class KnownLength as => IsProduct (p :: Type) (as :: [Type]) {--- | p -> as ---}
where
fromHList :: HList as -> p
toHList :: p -> HList as
instance KnownLength as => IsProduct (HList as) as where
fromHList = id
toHList = id
-- TODO: refactor this using 'Data.Constraint.All'
data AreProductsDict js iss as where
NilProducts :: AreProductsDict '[] '[] as
ConsProducts
:: ( IsProduct j is
, All PrimTy is
, AreProducts js iss as
, SameLength is (Distribute iss as)
)
=> AreProductsDict (j ': js) (is ': iss) as
class SameLength js iss
=> AreProducts (js :: [Type]) (iss :: [[Type]]) (as :: [Type]) {--- | js -> iss ---}
where
productsDict :: AreProductsDict js iss as
instance AreProducts '[] '[] as where
productsDict = NilProducts
instance (IsProduct j is, AreProducts js iss as, SameLength is (Distribute iss as), All PrimTy is)
=> AreProducts (j ': js) (is ': iss) as where
productsDict = ConsProducts
type family MapHList (iss :: [[Type]]) = (as :: [Type]) | as -> iss where
MapHList '[] = '[]
MapHList (is ': iss) = HList is ': MapHList iss
type family Distribute (iss :: [[Type]]) (as :: [Type]) = (jss :: [[Type]]) where
Distribute '[] '[] = '[]
Distribute '[] (a ': as) = '[] ': Distribute '[] as
Distribute (is ': iss) as = ZipCons is (Distribute iss as)
distributeZipConsLemma1
:: forall (a :: Type) (as :: [Type]) (ds :: [Type]) (dss :: [[Type]]) (es :: [Type]) (ess :: [[Type]])
. ( SameLength es ess
, (ds ': dss) ~ Distribute (ZipCons es ess) (a ': as)
)
=> ( ds :~: es, dss :~: Distribute ess as )
distributeZipConsLemma1 = ( unsafeCoerce Refl, unsafeCoerce Refl )
distributeZipConsLemma2
:: forall (as :: [Type]) (is :: [Type]) (iss :: [[Type]])
. ( SameLength is (Distribute iss as) )
=> ( ZipCons is (Distribute iss as) :~: Distribute (is ': iss) as )
distributeZipConsLemma2 = unsafeCoerce Refl
instance IsProduct a '[a] where
toHList x = x :> HNil
fromHList (x :> HNil) = x
instance IsProduct (a1,a2) '[a1,a2] where
toHList (x1,x2) = (x1 :> x2 :> HNil)
fromHList (x1 :> x2 :> HNil) = (x1,x2)
instance IsProduct (a1,a2,a3) '[a1,a2,a3] where
toHList (x1,x2,x3) = (x1 :> x2 :> x3 :> HNil)
fromHList (x1 :> x2 :> x3 :> HNil) = (x1,x2,x3)
instance IsProduct (a1,a2,a3,a4) '[a1,a2,a3,a4] where
toHList (x1,x2,x3,x4) = (x1 :> x2 :> x3 :> x4 :> HNil)
fromHList (x1 :> x2 :> x3 :> x4 :> HNil) = (x1,x2,x3,x4)
instance IsProduct (a1,a2,a3,a4,a5) '[a1,a2,a3,a4,a5] where
toHList (x1,x2,x3,x4,x5) = (x1 :> x2 :> x3 :> x4 :> x5 :> HNil)
fromHList (x1 :> x2 :> x3 :> x4 :> x5 :> HNil) = (x1,x2,x3,x4,x5)
instance IsProduct (a1,a2,a3,a4,a5,a6) '[a1,a2,a3,a4,a5,a6] where
toHList (x1,x2,x3,x4,x5,x6) = (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> HNil)
fromHList (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> HNil) = (x1,x2,x3,x4,x5,x6)
instance IsProduct (a1,a2,a3,a4,a5,a6,a7) '[a1,a2,a3,a4,a5,a6,a7] where
toHList (x1,x2,x3,x4,x5,x6,x7) = (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> x7 :> HNil)
fromHList (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> x7 :> HNil) = (x1,x2,x3,x4,x5,x6,x7)
instance IsProduct (a1,a2,a3,a4,a5,a6,a7,a8) '[a1,a2,a3,a4,a5,a6,a7,a8] where
toHList (x1,x2,x3,x4,x5,x6,x7,x8) = (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> x7 :> x8 :> HNil)
fromHList (x1 :> x2 :> x3 :> x4 :> x5 :> x6 :> x7 :> x8 :> HNil) = (x1,x2,x3,x4,x5,x6,x7,x8)