{- |
   The HList library

   (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke

   Declarations for various classes and functions that
   apply for the whole range of heterogeneous collections
   (HList, TIP, records, etc).
 -}

module Data.HList.HListPrelude where

import Data.HList.FakePrelude


class HExtend e l where
  type HExtendR e l
  (.*.) :: e -> l -> HExtendR e l

infixr 2 .*.


-- | to keep types shorter, '.*.' used with Proxy avoids
-- producing a @Proxy :: Proxy '[Label x,Label y,Label z]@
-- if @Proxy :: Proxy '[x,y,z]@ is not a kind error (as it
-- is when mixing Label6 and Label3 labels).
--
-- ghc-7.6 does not accept @Proxy ('[] :: [k])@ so for now
-- require @k ~ *@
instance HExtend (Label x) (Proxy ('[] :: [*])) where
    type HExtendR (Label x) (Proxy ('[] :: [*])) = Proxy '[x]
    (.*.) _ _ = Proxy


-- | similar to 'emptyRecord', 'emptyTIP', emptyHList (actually called 'HNil'),
-- except emptyProxy is the rightmost argument to '.*.'
emptyProxy = Proxy :: Proxy ('[] :: [*])

-- Poly-kinded
class SubType l l'

-- subType :: SubType l l' => l -> l' -> ()
-- subType _ _ = ()

class HAppend l1 l2 where
  hAppend :: l1 -> l2 -> HAppendR l1 l2

-- | poly-kinded, but 'hAppend' only works in cases where the kind variable
-- `k` is `*`
type family HAppendR (l1::k) (l2::k) :: k
-- class HMember e1 l (b :: Bool) | e1 l -> b

-- One occurrence and nothing is left
class HOccurs e l where
  hOccurs :: l -> e

-- Class to test that a type is "free" in a type sequence
-- polykinded
class HOccursNot (e :: k) (l :: [k])

class HProject l l' where
  hProject :: l -> l'

-- | Map a type (key) to a natural (index) within the collection
-- This is a purely type-level computation
class HType2HNat (e :: k) (l :: [k]) (n :: HNat) | e l -> n

--  | and lift to the list of types
class HTypes2HNats es l (ns :: [HNat]) | es l -> ns

-- | Delete all elements with the type-level key e from the
-- collection l. Since the key is type-level, it is represented
-- by a Proxy.
-- (polykinded)

class HDeleteMany e l l' | e l -> l' where
  hDeleteMany :: Proxy e -> l -> l'


class HDeleteAtLabel (r :: [*] -> *) (l :: k) v v' | l v -> v' where
    hDeleteAtLabel :: Label l -> r v -> r v'




-- | 'unzip'
class SameLengths [x,y,xy] => HUnzip (r :: [*] -> *) x y xy
        | x y -> xy, xy -> x y where
  hUnzip :: r xy -> (r x, r y)

-- | 'zip'. Variant supports hUnzip, but not hZip ('hZipVariant' returns a Maybe)
class HUnzip r x y xy => HZip (r :: [*] -> *) x y xy where
  hZip :: r x -> r y -> r xy