{-# LANGUAGE ConstraintKinds      #-}
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE EmptyCase            #-}
# LANGUAGE FlexibleContexts      #
{-# LANGUAGE GADTs                #-}
{-# LANGUAGE PolyKinds            #-}
{-# LANGUAGE RankNTypes           #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeFamilies         #-}
# LANGUAGE TypeOperators         #
# LANGUAGE UndecidableInstances #
module Data.SOP.Fn.LiftA2Cons (
    -- * Type families
    LiftA2Cons,
  * 
    liftA2Cons_NS,
    unliftA2Cons_NS,
    -- * Proxies
    prLiftA2Cons,
    -- * Constraints
    allLiftA2Cons,
    ) where

import Data.Bifunctor (first)
import Data.SOP
import Data.SOP.Fn.All
import Data.SOP.Fn.Append
import Data.SOP.Fn.MapCons
import Data.SOP.Sh

-------------------------------------------------------------------------------
-- Type family
-------------------------------------------------------------------------------

-- |
--
  Defined in " Data . SOP.Fn . LiftA2Cons " module
type family LiftA2Cons (xs :: [k]) (yss :: [[k]]) :: [[k]] where
    LiftA2Cons '[]       yss = '[]
    LiftA2Cons (x ': xs) yss = Append (MapCons x yss) (LiftA2Cons xs yss)

-------------------------------------------------------------------------------
  
-------------------------------------------------------------------------------

liftA2Cons_NS :: forall xs yss f. (SListI xs, SListI2 yss) => NS f xs -> NS (NP f) yss -> NS (NP f) (LiftA2Cons xs yss)
liftA2Cons_NS ns yss = case shTop ns of
    ShNil -> case ns of {}
    ShCons x xs -> case ns of
        Z z  -> allMapCons prTop x prYss $ injLeft (prLiftA2Cons xs prYss) $ mapCons_NSNP z yss
        S zs -> allMapCons prTop x prYss $ injRight (prMapCons x prYss) $ liftA2Cons_NS zs yss
  where
    prYss = Proxy :: Proxy yss

unliftA2Cons_NS :: forall xs yss f. (SListI xs, SListI2 yss) => NS (NP f) (LiftA2Cons xs yss) -> (NS f xs, NS (NP f) yss)
unliftA2Cons_NS ns = case shTop (Proxy :: Proxy xs) of
    ShNil -> case ns of {}
    ShCons prX _ -> allMapCons prTop prX prYss $ case split_NS ns of 
        Left l  -> first Z $ unmapCons_NSNP l
        Right r -> first S $ unliftA2Cons_NS r
  where
    prYss = Proxy :: Proxy yss

-------------------------------------------------------------------------------
-- Proxies
-------------------------------------------------------------------------------

prLiftA2Cons :: proxy xs -> proxy' yss -> Proxy (LiftA2Cons xs yss)
prLiftA2Cons _ _  = Proxy

-------------------------------------------------------------------------------
-- Constraints
-------------------------------------------------------------------------------

allLiftA2Cons
    :: (All c xs, All2 c yss)
    => proxyC c -> proxy xs -> proxy' yss
    -> (All2 c (LiftA2Cons xs yss) => r)
    -> r
allLiftA2Cons c0 xs0 yss0 = go c0 (sh xs0) yss0 where
    go :: (All c xs, All2 c yss) => proxyC c -> Sh xs -> proxy' yss -> (All2 c (LiftA2Cons xs yss) => r) -> r
    go _ ShNil         _   k = k
    go c (ShCons x xs) yss k
        = allMapCons c x yss
        $ go c (sh xs) yss
        $ allAppend (prAll c) (prMapCons x yss) (prLiftA2Cons xs yss) k 

# LANGUAGE ConstraintKinds      #
# LANGUAGE DataKinds            #
# LANGUAGE EmptyCase            #
# LANGUAGE GADTs                #
# LANGUAGE PolyKinds            #
# LANGUAGE RankNTypes           #
# LANGUAGE ScopedTypeVariables  #
# LANGUAGE TypeFamilies         #
 * Type families
 * Proxies
 * Constraints
-----------------------------------------------------------------------------
 Type family
-----------------------------------------------------------------------------
 |

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
 Proxies
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
 Constraints
-----------------------------------------------------------------------------
# LANGUAGE FlexibleContexts      #
# LANGUAGE TypeOperators         #
# LANGUAGE UndecidableInstances #
module Data.SOP.Fn.LiftA2Cons (
    LiftA2Cons,
  * 
    liftA2Cons_NS,
    unliftA2Cons_NS,
    prLiftA2Cons,
    allLiftA2Cons,
    ) where

import Data.Bifunctor (first)
import Data.SOP
import Data.SOP.Fn.All
import Data.SOP.Fn.Append
import Data.SOP.Fn.MapCons
import Data.SOP.Sh


  Defined in " Data . SOP.Fn . LiftA2Cons " module
type family LiftA2Cons (xs :: [k]) (yss :: [[k]]) :: [[k]] where
    LiftA2Cons '[]       yss = '[]
    LiftA2Cons (x ': xs) yss = Append (MapCons x yss) (LiftA2Cons xs yss)

  

liftA2Cons_NS :: forall xs yss f. (SListI xs, SListI2 yss) => NS f xs -> NS (NP f) yss -> NS (NP f) (LiftA2Cons xs yss)
liftA2Cons_NS ns yss = case shTop ns of
    ShNil -> case ns of {}
    ShCons x xs -> case ns of
        Z z  -> allMapCons prTop x prYss $ injLeft (prLiftA2Cons xs prYss) $ mapCons_NSNP z yss
        S zs -> allMapCons prTop x prYss $ injRight (prMapCons x prYss) $ liftA2Cons_NS zs yss
  where
    prYss = Proxy :: Proxy yss

unliftA2Cons_NS :: forall xs yss f. (SListI xs, SListI2 yss) => NS (NP f) (LiftA2Cons xs yss) -> (NS f xs, NS (NP f) yss)
unliftA2Cons_NS ns = case shTop (Proxy :: Proxy xs) of
    ShNil -> case ns of {}
    ShCons prX _ -> allMapCons prTop prX prYss $ case split_NS ns of 
        Left l  -> first Z $ unmapCons_NSNP l
        Right r -> first S $ unliftA2Cons_NS r
  where
    prYss = Proxy :: Proxy yss


prLiftA2Cons :: proxy xs -> proxy' yss -> Proxy (LiftA2Cons xs yss)
prLiftA2Cons _ _  = Proxy


allLiftA2Cons
    :: (All c xs, All2 c yss)
    => proxyC c -> proxy xs -> proxy' yss
    -> (All2 c (LiftA2Cons xs yss) => r)
    -> r
allLiftA2Cons c0 xs0 yss0 = go c0 (sh xs0) yss0 where
    go :: (All c xs, All2 c yss) => proxyC c -> Sh xs -> proxy' yss -> (All2 c (LiftA2Cons xs yss) => r) -> r
    go _ ShNil         _   k = k
    go c (ShCons x xs) yss k
        = allMapCons c x yss
        $ go c (sh xs) yss
        $ allAppend (prAll c) (prMapCons x yss) (prLiftA2Cons xs yss) k 
