packages feed

tuple-ops 0.0.0.0 → 0.0.0.1

raw patch · 3 files changed

+129/−125 lines, 3 filesdep +type-combinators

Dependencies added: type-combinators

Files

src/Data/Tuple/Ops/Internal.hs view
@@ -13,139 +13,125 @@ -- representation of tuple.
 ------------------------------------------------------------
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Data.Tuple.Ops.Internal where
 
-import qualified GHC.Generics as G
-import GHC.Generics (Generic(..), (:*:)(..), (:+:)(..), Rec0, C1, D1, S1, M1(..), U1, K1(..))
-import GHC.TypeLits
+import GHC.Generics ((:*:)(..), Rec0, D1, S1, Meta(..), SourceUnpackedness(..), SourceStrictness(..), DecidedStrictness(..))
 import Data.Proxy
-import qualified Prelude as P 
-import Prelude (Maybe(..), Int, Word, Char, Float, Double, Bool(..), ($))
+import Data.Type.Combinator
+import Data.Type.Product
+import Type.Family.List
+import Type.Class.Witness
+import qualified Type.Family.Nat as Nat
 
--- | a sentinial datatype that represents a empty product
-data End a = End
+-- 'TupleR' is an injective type that @TupleR f x == TupleR g y ---> f == g && x == y@
+newtype TupleR (f :: [* -> *]) x = TupleR { unTupleR :: Tuple (f <&> x)}
 
--- | Representation of tuple are shaped in a balanced tree. 
--- 'L' transforms the tree into a line, for further manipulation.
-class Linearize (t :: * -> *) (b :: * -> *) where
-  type L t b :: * -> *
-  linearize :: t x -> b x -> L t b x
+-- | prove that @(a ++ b) <&> x == a <&> x ++ b <&> x@
+class AppDistributive (a :: [* -> *]) where
+    appDistrWit :: (Proxy a, Proxy b, Proxy x) -> Wit (((a ++ b) <&> x) ~ ((a <&> x) ++ (b <&> x)))
+-- | inductive proof on @a@
+-- case 1. @a@ is @[]@
+instance AppDistributive '[] where
+    appDistrWit _ = Wit
+-- | case 2. @a@ is @_ :< _@
+instance AppDistributive as => AppDistributive (a :< as) where
+    appDistrWit (_ :: Proxy (a :< as), pb, px) = 
+        case appDistrWit (Proxy :: Proxy as, pb, px) of 
+            Wit -> Wit
 
--- | base case 1. cons field with end
-instance Linearize (S1 MetaS (Rec0 t)) End where
-    type L (S1 MetaS (Rec0 t)) End = (S1 MetaS (Rec0 t))
-    linearize a End = a
+-- | utility function to call 'appDistrWit'
+appDistrWitPassArg :: (f :*: g) x -> (Proxy (L f), Proxy (L g), Proxy x)
+appDistrWitPassArg _ = (Proxy, Proxy, Proxy)
 
--- note that it is not possible to combine base case 2 and 3, which results in
--- a ambiguous instantiation with base case 1
---
--- | base case 2. cons field1 with field2 
-instance Linearize (S1 MetaS (Rec0 t)) (S1 MetaS (Rec0 b)) where
-    type L (S1 MetaS (Rec0 t)) (S1 MetaS (Rec0 b)) = S1 MetaS (Rec0 t) :*: S1 MetaS (Rec0 b)
-    linearize a b = a :*: b
+-- | Representation of tuple are shaped in a balanced tree. 
+-- 'L' transforms the tree into a list, for further manipulation.
+class Linearize (t :: * -> *) where
+  type L t :: [* -> *]
+  linearize :: t x -> TupleR (L t) x
 
--- | base case 3. cons field1 with a product
-instance Linearize (S1 MetaS (Rec0 t)) (b :*: c) where
-    type L (S1 MetaS (Rec0 t)) (b :*: c) = S1 MetaS (Rec0 t) :*: b :*: c
-    linearize a b = a :*: b
+-- | base case. sinleton
+instance Linearize (S1 MetaS (Rec0 t)) where
+    type L (S1 MetaS (Rec0 t)) = '[S1 MetaS (Rec0 t)]
+    linearize = TupleR . only . I
 
 -- | inductive case. preppend a product with what ever
-instance (Linearize v b, Linearize u (L v b)) => Linearize (u :*: v) b where
-    type L (u :*: v) b = L u (L v b)
-    linearize (a :*: b) c = linearize a (linearize b c)
+instance (Linearize v, Linearize u, AppDistributive (L u)) => Linearize (u :*: v) where
+    type L (u :*: v) = L u ++ L v
+    linearize (a :*: b) = 
+        case appDistrWit (appDistrWitPassArg (a :*: b)) of
+            Wit -> TupleR $ append' (unTupleR $ linearize a) (unTupleR $ linearize b)
 
--- | calculate the number of fields of a product
--- note: undefined on non-product rep
-type family Length a :: Nat where
-    Length (S1 MetaS (Rec0 t)) = 1
-    Length (a :*: b) = Length a + Length b
--- | calculate the number of fields of a product
-length :: a x -> Proxy (Length a)
-length _ = Proxy
+length' :: TupleR a x -> Proxy (Nat.Len a)
+length' _ = Proxy
 
 -- | calculate the half
-type family Half (a :: Nat) :: Nat where
-    Half 1 = 0
-    Half 2 = 1
-    Half n = Half (n - 2) + 1
+type family Half (a :: Nat.N) :: Nat.N where
+    Half ('Nat.S 'Nat.Z) = 'Nat.Z
+    Half ('Nat.S ('Nat.S 'Nat.Z)) = 'Nat.S 'Nat.Z
+    Half ('Nat.S ('Nat.S n)) = 'Nat.S (Half n)
 -- | calculate the half
-half :: KnownNat n => Proxy n -> Proxy (Half n)
+half :: Proxy n -> Proxy (Half n)
 half _ = Proxy
 
--- | Positive natural number in type level
--- We rely on the SNat to define Take and Drop
-data SNat = One | Succ SNat
--- | transform the GHC's typelit into SNat
-type family ToSNat (a :: Nat) :: SNat where
-    ToSNat 1 = One
-    ToSNat n = Succ (ToSNat (n - 1))
--- | transform the GHC's typelit into SNat
-tosnat :: KnownNat n => Proxy n -> Proxy (ToSNat n)
-tosnat _ = Proxy
-
 -- | take the first n elements from a product
-class Take (n :: SNat) (a :: * -> *) where
-    type T n a :: * -> *
-    take :: Proxy n -> a x -> T n a x
-
--- | base case 1. take one out of singleton
-instance Take One (S1 MetaS (Rec0 t)) where
-    type T One (S1 MetaS (Rec0 t)) = S1 MetaS (Rec0 t)
-    take _ a = a
+class Take (n :: Nat.N) (a :: [* -> *]) where
+    type T n a :: [* -> *]
+    take' :: Proxy n -> TupleR a x -> TupleR (T n a) x
 
--- | base case 2. take one out of a product
-instance Take One (a :*: b) where
-    type T One (a :*: b) = a
-    take _ (a :*: _) = a
+-- | base case. take one out of singleton
+instance Take 'Nat.Z xs where
+    type T 'Nat.Z xs = '[]
+    take' _ _ = TupleR Ø
 
 -- | inductive case. take (n+1) elements
-instance Take n b => Take (Succ n) (a :*: b) where
-    type T (Succ n) (a :*: b) = a :*: T n b
-    take (_ :: Proxy (Succ n)) (a :*: b) = a :*: take (Proxy :: Proxy n) b
+instance Take n as => Take ('Nat.S n) (a : as) where
+    type T ('Nat.S n) (a : as) = a : T n as
+    take' (_ :: Proxy ('Nat.S n)) (TupleR (a :< as) :: TupleR (a : as) x) = 
+        let as' = unTupleR $ take' (Proxy :: Proxy n) (TupleR as :: TupleR as x)
+        in TupleR (a :< as')
 
 -- | drop the first n elements from a product
-class Drop (n :: SNat) (a :: * -> *) where
-    type D n a :: * -> *
-    drop :: Proxy n -> a x -> D n a x
+class Drop (n :: Nat.N) (a :: [* -> *]) where
+    type D n a :: [* -> *]
+    drop' :: Proxy n -> TupleR a x -> TupleR (D n a) x
 
--- | base case 1. drop one from product
-instance Drop One (a :*: b) where
-    type D One (a :*: b) = b
-    drop _ (_ :*: b) = b
+-- | base case. drop one from product
+instance Drop 'Nat.Z as where
+    type D 'Nat.Z as = as
+    drop' _ a = a
 
 -- | inductive case. drop (n+1) elements
-instance Drop n b => Drop (Succ n) (a :*: b) where
-    type D (Succ n) (a :*: b) = D n b
-    drop (_ :: Proxy (Succ n)) (a :*: b) = drop (Proxy :: Proxy n) b
+instance Drop n as => Drop ('Nat.S n) (a : as) where
+    type D ('Nat.S n) (a : as) = D n as
+    drop' (_ :: Proxy ('Nat.S n)) (TupleR (a :< as) :: TupleR (a : as) x) = 
+        drop' (Proxy :: Proxy n) (TupleR as :: TupleR as x)
 
 -- | 'Normalize' converts a linear product back into a balanced tree.
-class Normalize (a :: * -> *) where
-    type N a :: * -> * 
-    normalize :: a x -> N a x
+class Normalize (a :: [* -> *]) where
+    type N a :: * -> *
+    normalize :: TupleR a x -> N a x
 
--- | base case 1. singleton
-instance Normalize (S1 MetaS (Rec0 t)) where
-    type N (S1 MetaS (Rec0 t)) = S1 MetaS (Rec0 t)
-    normalize a = a
+-- | base case. singleton
+instance Normalize '[S1 MetaS (Rec0 t)] where
+    type N '[S1 MetaS (Rec0 t)] = S1 MetaS (Rec0 t)
+    normalize a = getI $ head' $ unTupleR a
 
 -- | inductive case. product
-instance (KnownNat (Length a + Length b),
-          KnownNat (Half (Length a + Length b)),
-          Take (ToSNat (Half (Length a + Length b))) (a :*: b),
-          Drop (ToSNat (Half (Length a + Length b))) (a :*: b),
-          Normalize ((T (ToSNat (Half (Length a + Length b))) (a :*: b))), 
-          Normalize ((D (ToSNat (Half (Length a + Length b))) (a :*: b)))) 
-    => Normalize (a :*: b) where
-    type N (a :*: b) = N (T (ToSNat (Half (Length a + Length b))) (a :*: b)) :*: 
-                       N (D (ToSNat (Half (Length a + Length b))) (a :*: b))
-    normalize v = let n1 = length v :: Proxy (Length a + Length b)
-                      n2 = tosnat $ half n1
-                  in normalize (take n2 v) :*: normalize (drop n2 v)
+instance (Take (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c),
+          Drop (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c),
+          Normalize (T (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c)), 
+          Normalize (D (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c))) 
+    => Normalize (a :< b :< c) where
+    type N (a :< b :< c) = N (T (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c)) :*: 
+                           N (D (Half (Nat.N2 Nat.+ Nat.Len c)) (a :< b :< c))
+    normalize v = let n = half (length' v)
+                  in normalize (take' n v) :*: normalize (drop' n v)
 
-type MetaS = 'G.MetaSel 'Nothing 'G.NoSourceUnpackedness 'G.NoSourceStrictness 'G.DecidedLazy
+type MetaS = 'MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy
 -- | utility type function to trim the Rec0 
 type family UnRec0 t where
     UnRec0 (Rec0 t) = t
@@ -155,3 +141,6 @@ -- | utility type function to trim the D1
 type family UnD1 t where
     UnD1 (D1 _ t) = t
+-- | utility type function to extract the meta information
+type family MetaOfD1 t where
+    MetaOfD1 (D1 m _) = m
src/Data/Tuple/Ops/Uncons.hs view
@@ -22,31 +22,35 @@ --
 ------------------------------------------------------------
 {-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
 
-module Data.Tuple.Ops.Uncons (uncons, Uncons) where
+module Data.Tuple.Ops.Uncons (uncons, Uncons, Unconsable) where
 
-import qualified GHC.Generics as G
-import GHC.Generics (Generic(..), (:*:)(..), (:+:)(..), Rec0, C1, D1, S1, M1(..), U1, K1(..))
-import GHC.TypeLits
+import GHC.Generics (Generic(..), (:*:)(..), (:+:)(..), URec, Rec0, C1, D1, S1, M1(..), U1, K1(..), Meta(..), FixityI(..))
+import GHC.TypeLits (Symbol)
+import Data.Proxy
+import Type.Family.Nat (N1)
 import Data.Tuple.Ops.Internal
 
 -- | representation of a pair
-type RepOfPair t1 t2 = C1 ('G.MetaCons "(,)" 'G.PrefixI 'False) (S1 MetaS (Rec0 t1) :*: S1 MetaS (Rec0 t2))
+type RepOfPair t1 t2 = C1 ('MetaCons "(,)" 'PrefixI 'False) (S1 MetaS (Rec0 t1) :*: S1 MetaS (Rec0 t2))
 -- | representation of a tuple of arity > 2, in which @/u/@ is of the form @_ :*: _@
-type RepOfTuple c u = C1 ('G.MetaCons c 'G.PrefixI 'False) u 
+type RepOfTuple c u = C1 ('MetaCons c 'PrefixI 'False) u 
 
 -- | 'HeadR' is a type function that takes the first element of a tuple
 type family HeadR (f :: * -> *) :: * -> * where
-    HeadR (C1 mc (S1 ms (G.URec a))) = C1 mc (S1 ms (G.URec a))
+    HeadR (C1 mc (S1 ms (URec a))) = C1 mc (S1 ms (URec a))
     HeadR (a :+: b) = a :+: b
     HeadR (RepOfPair t1 t2) = UnD1 (Rep t1)
-    HeadR (RepOfTuple tcon (a :*: b :*: c)) = UnD1 (Rep (UnRec0 (UnS1 (T One (L (a :*: b :*: c) End)))))
+    HeadR (RepOfTuple tcon (a :*: b :*: c)) = UnD1 (Rep (UnRec0 (UnS1 (N (T N1 (L (a :*: b :*: c)))))))
 -- | 'TailR' is a type function that drops the first element of a tuple
 type family TailR (f :: * -> *) :: * -> * where
-    TailR (C1 mc (S1 ms (G.URec a))) = C1 ('G.MetaCons "()" 'G.PrefixI 'False) U1
-    TailR (a :+: b) = C1 ('G.MetaCons "()" 'G.PrefixI 'False) U1
+    TailR (C1 mc (S1 ms (URec a))) = C1 ('MetaCons "()" 'PrefixI 'False) U1
+    TailR (a :+: b) = C1 ('MetaCons "()" 'PrefixI 'False) U1
     TailR (RepOfPair t1 t2) = UnD1 (Rep t2)
-    TailR (RepOfTuple tcon (a :*: b :*: c)) = RepOfTuple (TupleConPred tcon) (N (D One (L (a :*: b :*: c) End)))
+    TailR (RepOfTuple tcon (a :*: b :*: c)) = RepOfTuple (TupleConPred tcon) (N (D N1 (L (a :*: b :*: c))))
 
 -- | Abstract type class for generic representation of a /uncons/able datatype
 class UnconsR f where
@@ -55,7 +59,7 @@ -- | primitive datatype
 -- 'HeadR' is the datatype itself
 -- 'TailR' is ()
-instance UnconsR (C1 mc (S1 ms (G.URec a))) where
+instance UnconsR (C1 mc (S1 ms (URec a))) where
     unconsR a = (a, unM1 (from ()))
 
 -- | sum datatype
@@ -75,12 +79,17 @@ -- | tuple of arity > 2
 -- 'HeadR' is the first element
 -- 'TailR' is the rest all elements
-instance (Linearize c End, Linearize b (L c End), Linearize a (L b (L c End)),
-          L a (L b (L c End)) ~ (S1 MetaS (Rec0 t) :*: w), 
+instance (Linearize (a :*: b :*: c), L (a :*: b :*: c) ~ (S1 MetaS (Rec0 t) : w), 
           Generic t, Rep t ~ D1 hm hc, Normalize w) 
     => UnconsR (RepOfTuple tcon (a :*: b :*: c)) where
-    unconsR a = case linearize (unM1 a) End of
-                  u :*: v -> (unM1 $ from $ unK1 $ unM1 u, M1 $ normalize v)
+    unconsR a = let tup = linearize (unM1 a)
+                    one = Proxy :: Proxy N1
+                    h = unM1 $ from $ unK1 $ unM1 $ normalize $ take' one tup
+                    t = M1 $ normalize $ drop' one tup
+                in (h, t)
+    -- unconsR a = case linearize (unM1 a) of
+    --               (TupleR (u :< v) :: TupleR (S1 MetaS (Rec0 t) : w) x) -> 
+    --                 (unM1 $ from $ (unK1 (unM1 (getI u)) :: t), M1 $ normalize $ (TupleR v :: TupleR w x))
 
 -- | calculate the tuple constructor of the size 1 smaller
 -- upto the tupel of arity of 16
@@ -120,11 +129,17 @@     Uncons (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = (a, (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p))
     Uncons a = (a, ())
 
--- | 'uncons' takes primitive, pair, tuple
+-- | A constraint on any 'uncons'able data type, where
+-- @a@ is the input type, and @(b,c)@ is the output type
+type Unconsable a b c = (Generic a, Generic b, Generic c, Uncons a ~ (b, c),
+                         Rep a ~ D1 (MetaOfD1 (Rep a)) (UnD1 (Rep a)), 
+                         Rep b ~ D1 (MetaOfD1 (Rep b)) (UnD1 (Rep b)), 
+                         Rep c ~ D1 (MetaOfD1 (Rep c)) (UnD1 (Rep c)),
+                         UnconsR (UnD1 (Rep a)), 
+                         HeadR (UnD1 (Rep a)) ~ (UnD1 (Rep b)), 
+                         TailR (UnD1 (Rep a)) ~ (UnD1 (Rep c)))
+
+-- | 'uncons' takes primitive, pair, tuple,
 -- and produces a pair of its first data and the rest elements.
-uncons :: (Generic a, Rep a ~ D1 ma ra, Uncons a ~ (b, c),
-           Generic b, Rep b ~ D1 mb rb,
-           Generic c, Rep c ~ D1 mc rc,
-           UnconsR ra, HeadR ra ~ rb, TailR ra ~ rc)
-       => a -> Uncons a 
+uncons :: Unconsable a b c => a -> (b, c)
 uncons x = let (a, b) = unconsR $ unM1 $ from x in (to $ M1 a, to $ M1 b)
tuple-ops.cabal view
@@ -1,5 +1,5 @@ name:                       tuple-ops
-version:                    0.0.0.0
+version:                    0.0.0.1
 category:                   Data
 author:                     Jiasen Wu
 maintainer:                 Jiasen Wu <jiasenwu@hotmail.com>
@@ -21,6 +21,6 @@                           , TypeOperators
                           , KindSignatures
                           , TypeFamilies
-                          , UndecidableInstances
                           , FlexibleInstances
-    build-depends:          base >= 4.7 && < 5.0+    build-depends:          base >= 4.7 && < 5.0
+                          , type-combinators == 0.2.4.3