packages feed

free-foil-0.3.0: src/Data/ZipMatchK/Mappings.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneKindSignatures #-}
module Data.ZipMatchK.Mappings where

import           Data.Kind              (Type)
import           Generics.Kind

-- | Zip to lists of types into a single list of pair types.
type ZipLoT :: LoT k -> LoT k -> LoT k
type family ZipLoT as bs where
  ZipLoT LoT0 LoT0 = LoT0
  ZipLoT (a :&&: as) (b :&&: bs) = ((a, b) :&&: ZipLoT as bs)

infixr 5 :^:
type Mappings :: LoT k -> LoT k -> LoT k -> Type
-- | A collection of zipping functions for 'Data.ZipMatchK.zipMatchWithK'.
data Mappings (as :: LoT k) (bs :: LoT k) (cs :: LoT k) where
  -- | An empty collection (when there no (more) type parameters).
  M0 :: Mappings LoT0 LoT0 LoT0
  -- | A non-empty collection (when there is at least one type parameter).
  (:^:) :: (a -> b -> Maybe c)    -- ^ Zipping for the first type parameter.
        -> Mappings as bs cs      -- ^ Zipping for other type parameters.
        -> Mappings (a :&&: as) (b :&&: bs) (c :&&: cs)

class PairMappings (as :: LoT k) (bs :: LoT k) where
  -- | A collection of pairing functions @(\\x y -> Just (x, y))@ for 'Data.ZipMatchK.zipMatchK'.
  pairMappings :: Mappings as bs (ZipLoT as bs)

instance PairMappings LoT0 LoT0 where
  pairMappings = M0

instance PairMappings as bs => PairMappings ((a :: Type) :&&: as) ((b :: Type) :&&: bs) where
  pairMappings = pairA :^: pairMappings

class ApplyMappings (v :: TyVar d Type) where
  -- | Apply a collection of zipping functions to collections of values.
  applyMappings :: forall (as :: LoT d) (bs :: LoT d) (cs :: LoT d).
       Mappings as bs cs      -- ^ A collection of zipping functions.
    -> Interpret (Var v) as   -- ^ First collection of values (one per type parameter).
    -> Interpret (Var v) bs   -- ^ Second collection of values (one per type parameter).
    -> Maybe (Interpret (Var v) cs)

instance ApplyMappings (VZ :: TyVar (Type -> tys) Type) where
  applyMappings (f :^: _) x y = f x y

instance ApplyMappings v => ApplyMappings (VS v :: TyVar (ty -> tys) Type) where
  applyMappings (_ :^: fs) x y = applyMappings @_ @v fs x y

-- | Pair two values in a context.
pairA :: Applicative f => a -> b -> f (a, b)
pairA x y = pure (x, y)