{-# LANGUAGE GADTs #-} {-# LANGUAGE TypeOperators #-} module CheckTypes where import Data.Profunctor.Product (ProductProfunctor) import Data.Profunctor.Product.Default (Default, def) import Data.Profunctor.Product.Adaptor import Definitions (Data2, Data3, Record2, Record3, RecordDefaultName, Data2Inferrable(Data2Inferrable), Record2Inferrable(Record2Inferrable), pData2, pData3, pRecord2, pRecord3, pRecordDefaultName, unArrow, Unit(Unit), point) import DefinitionsUndecidable () -- The test suite checks that the TH derived adaptor is of the correct -- type and that the typeclass instance has been generated. We don't -- actually check the implementation since by parametricity I expect -- that only the order in which the product profunctors are combined -- can vary. pData2' :: ProductProfunctor p => Data2 (p a a') (p b b') -> p (Data2 a b) (Data2 a' b') pData2' = pData2 pData3' :: ProductProfunctor p => Data3 (p a a') (p b b') (p c c') -> p (Data3 a b c) (Data3 a' b' c') pData3' = pData3 pRecord2' :: ProductProfunctor p => Record2 (p a a') (p b b') -> p (Record2 a b) (Record2 a' b') pRecord2' = pRecord2 pRecord3' :: ProductProfunctor p => Record3 (p a a') (p b b') (p c c') -> p (Record3 a b c) (Record3 a' b' c') pRecord3' = pRecord3 instanceData2 :: (ProductProfunctor p, Default p a a', Default p b b') => p (Data2 a b) (Data2 a' b') instanceData2 = def instanceData3 :: (ProductProfunctor p, Default p a a', Default p b b', Default p c c') => p (Data3 a b c) (Data3 a' b' c') instanceData3 = def instanceRecord2 :: (ProductProfunctor p, Default p a a', Default p b b') => p (Record2 a b) (Record2 a' b') instanceRecord2 = def instanceRecord3 :: (ProductProfunctor p, Default p a a', Default p b b', Default p c c') => p (Record3 a b c) (Record3 a' b' c') instanceRecord3 = def defaultNameGenerated :: ProductProfunctor p => RecordDefaultName (p x x') (p y y') -> p (RecordDefaultName x y) (RecordDefaultName x' y') defaultNameGenerated = pRecordDefaultName -- We similarly test the type of the generic adaptor. pData2G :: ProductProfunctor p => Data2 (p a a') (p b b') -> p (Data2 a b) (Data2 a' b') pData2G = genericAdaptor pData3G :: ProductProfunctor p => Data3 (p a a') (p b b') (p c c') -> p (Data3 a b c) (Data3 a' b' c') pData3G = genericAdaptor pRecord2G :: ProductProfunctor p => Record2 (p a a') (p b b') -> p (Record2 a b) (Record2 a' b') pRecord2G = pRecord2 pRecord3G :: ProductProfunctor p => Record3 (p a a') (p b b') (p c c') -> p (Record3 a b c) (Record3 a' b' c') pRecord3G = pRecord3 -- Can type inference information flow from the left type argument of -- a Profunctor to the right? inferDataLR :: () inferDataLR = const () (unArrow def (Data2Inferrable Unit Unit)) inferRecordLR :: () inferRecordLR = const () (unArrow def (Record2Inferrable Unit Unit)) inferTupleLR :: () inferTupleLR = const () (unArrow def (Unit, Unit)) -- Can type inference information flow from the right type argument of -- a Profunctor to the left? inferDataRL :: () inferDataRL = case unArrow def point of Data2Inferrable Unit Unit -> () inferRecordRL :: () inferRecordRL = case unArrow def point of Record2Inferrable Unit Unit -> () inferTupleRL :: () inferTupleRL = case unArrow def point of (Unit, Unit) -> () data a :~: b where Refl :: a :~: a pData2TypeEq :: (Data2 (p a a') (p b b') -> p (Data2 a b) (Data2 a' b')) :~: Adaptor p (Data2 (p a a') (p b b')) pData2TypeEq = Refl pData3TypeEq :: (Data3 (p a a') (p b b') (p c c') -> p (Data3 a b c) (Data3 a' b' c')) :~: Adaptor p (Data3 (p a a') (p b b') (p c c')) pData3TypeEq = Refl