{-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} -- | Standard representation of n-ary products. module Generics.MRSOP.Base.NP where import Generics.MRSOP.Util infixr 5 :* -- |Indexed n-ary products. This is analogous to the @All@ datatype -- in Agda. data NP :: (k -> *) -> [k] -> * where NP0 :: NP p '[] (:*) :: p x -> NP p xs -> NP p (x : xs) instance Eq1 ki => Eq1 (NP ki) where eq1 = eqNP eq1 -- * Relation to IsList predicate -- |Append two values of type 'NP' appendNP :: NP p xs -> NP p ys -> NP p (xs :++: ys) appendNP NP0 ays = ays appendNP (a :* axs) ays = a :* appendNP axs ays -- |Proves that the index of a value of type 'NP' is a list. -- This is useful for pattern matching on said list without -- having to carry the product around. listPrfNP :: NP p xs -> ListPrf xs listPrfNP NP0 = Nil listPrfNP (_ :* xs) = Cons $ listPrfNP xs -- * Map, Elim and Zip -- |Maps a natural transformation over a n-ary product mapNP :: f :-> g -> NP f ks -> NP g ks mapNP f NP0 = NP0 mapNP f (k :* ks) = f k :* mapNP f ks -- |Maps a monadic natural transformation over a n-ary product mapNPM :: (Monad m) => (forall x . f x -> m (g x)) -> NP f ks -> m (NP g ks) mapNPM f NP0 = return NP0 mapNPM f (k :* ks) = (:*) <$> f k <*> mapNPM f ks -- |Eliminates the product using a provided function. elimNP :: (forall x . f x -> a) -> NP f ks -> [a] elimNP f NP0 = [] elimNP f (k :* ks) = f k : elimNP f ks -- |Monadic eliminator elimNPM :: (Monad m) => (forall x . f x -> m a) -> NP f ks -> m [a] elimNPM f NP0 = return [] elimNPM f (k :* ks) = (:) <$> f k <*> elimNPM f ks -- |Combines two products into one. zipNP :: NP f xs -> NP g xs -> NP (f :*: g) xs zipNP NP0 NP0 = NP0 zipNP (f :* fs) (g :* gs) = (f :*: g) :* zipNP fs gs -- * Catamorphism -- |Consumes a value of type 'NP'. cataNP :: (forall x xs . f x -> r xs -> r (x : xs)) -> r '[] -> NP f xs -> r xs cataNP fCons fNil NP0 = fNil cataNP fCons fNil (k :* ks) = fCons k (cataNP fCons fNil ks) -- * Equality -- |Compares two 'NP's pairwise with the provided function and -- return the conjunction of the results. eqNP :: (forall x. p x -> p x -> Bool) -> NP p xs -> NP p xs -> Bool eqNP p x = and . elimNP (uncurry' p) . zipNP x