module Data.Existential where
import Control.Applicative as A
import Control.Lens
import Control.Monad
import Data.Maybe
import Data.Typeable
import GHC.Exts (Constraint)
import Language.Haskell.TH
import Test.QuickCheck
import Text.Printf
type Cell = Cell1 Identity
data Cell1 f (constr :: * -> Constraint) = forall a. (constr a, Typeable a) => Cell (f a)
class HasCell a b | a -> b where
cell :: Iso' a b
instance HasCell (Cell1 f constr) (Cell1 f constr) where
cell = id
makeCell :: (HasCell a (Cell constr), constr b, Typeable b)
=> b -> a
makeCell = makeCell1 . Identity
makeCell1 :: (HasCell a (Cell1 f constr), constr b, Typeable b)
=> f b -> a
makeCell1 x = Cell x ^. from cell
_Cell :: (constr b,Typeable b,Typeable a) => Prism (Cell constr) (Cell constr) a b
_Cell = _Cell1._Wrapped
_Cell' :: (constr a,Typeable a,HasCell c (Cell constr)) => Prism c c a a
_Cell' = cell.asCell
_Cell1 :: (constr b,Typeable b,Typeable a,Typeable f)
=> Prism (Cell1 f constr) (Cell1 f constr) (f a) (f b)
_Cell1 = prism Cell $ \x -> maybe (Left x) Right $ readCell1 cast x
_Cell1' :: (constr a,Typeable a,Typeable f,HasCell c (Cell1 f constr)) => Prism c c (f a) (f a)
_Cell1' = cell.asCell1
asCell :: (constr a,Typeable a) => Prism (Cell constr) (Cell constr) a a
asCell = _Cell
asCell1 :: (constr a,Typeable a,Typeable f) => Prism (Cell1 f constr) (Cell1 f constr) (f a) (f a)
asCell1 = _Cell1
traverseCell :: Functor f => (forall a. (constr a,Typeable a) => a -> f a)
-> Cell constr -> f (Cell constr)
traverseCell f = traverseCell1 $ _Wrapped f
traverseCell' :: (Functor f,HasCell c (Cell constr))
=> (forall a. (constr a,Typeable a) => a -> f a) -> c -> f c
traverseCell' f = cell (traverseCell f)
traverseCell1 :: Functor f => (forall a. (constr a,Typeable a) => g a -> f (h a))
-> Cell1 g constr -> f (Cell1 h constr)
traverseCell1 f (Cell x) = Cell <$> f x
traverseCell1' :: (Functor f,HasCell c (Cell1 g constr))
=> (forall a. (constr a,Typeable a) => g a -> f (g a)) -> c -> f c
traverseCell1' f = cell (traverseCell1 f)
mapCell :: (forall a. (constr a,Typeable a) => a -> a) -> Cell constr -> Cell constr
mapCell f = runIdentity . traverseCell (Identity . f)
mapCell' :: HasCell c (Cell constr)
=> (forall a. (constr a,Typeable a) => a -> a)
-> c -> c
mapCell' f x = mapCell f (x^.cell) ^. from cell
readCell1 :: (forall a. (constr a,Typeable a) => f a -> r) -> Cell1 f constr -> r
readCell1 = readCell1'
readCell1' :: HasCell c (Cell1 f constr)
=> (forall a. (constr a,Typeable a) => f a -> r)
-> c -> r
readCell1' f = getConst . traverseCell1' (Const . f)
readCell :: (forall a. (constr a,Typeable a) => a -> r) -> Cell constr -> r
readCell f = getConst . traverseCell (Const . f)
readCell' :: HasCell c (Cell constr)
=> (forall a. (constr a,Typeable a) => a -> r)
-> c -> r
readCell' f x = readCell f $ x^.cell
apply2Cells :: Functor f
=> (forall a. (constr a,Typeable a)
=> a -> a -> f a)
-> f (Cell constr)
-> Cell constr -> Cell constr
-> f (Cell constr)
apply2Cells f = apply2Cells1 (\(Identity x) (Identity y) -> Identity <$> f x y)
apply2Cells' :: (Functor f,HasCell c (Cell constr))
=> (forall a. (constr a,Typeable a)
=> a -> a -> f a)
-> f c -> c -> c -> f c
apply2Cells' f def x y = view (from cell) <$> apply2Cells f (view cell <$> def) (x^.cell) (y^.cell)
apply2Cells1 :: (Functor f,Typeable g)
=> (forall a. (constr a,Typeable a)
=> g a -> g a -> f (g a))
-> f (Cell1 g constr)
-> Cell1 g constr -> Cell1 g constr
-> f (Cell1 g constr)
apply2Cells1 f def (Cell x) (Cell y) = fromMaybe def $ fmap Cell . f x <$> cast y
apply2Cells1' :: (Functor f,Typeable g,HasCell c (Cell1 g constr))
=> (forall a. (constr a,Typeable a)
=> g a -> g a -> f (g a))
-> f c
-> c -> c
-> f c
apply2Cells1' f def x y = view (from cell) <$> apply2Cells1 f (view cell <$> def) (x^.cell) (y^.cell)
map2Cells :: (forall a. (constr a,Typeable a)
=> a -> a -> a)
-> Cell constr -> Cell constr -> Cell constr
-> Cell constr
map2Cells f def x y = runIdentity $ apply2Cells (fmap pure . f) (pure def) x y
map2Cells' :: HasCell c (Cell constr)
=> (forall a. (constr a,Typeable a)
=> a -> a -> a)
-> c -> c -> c -> c
map2Cells' f def x y = view (from cell) $ map2Cells f (def^.cell) (x^.cell) (y^.cell)
map2Cells1 :: (forall a. (constr a,Typeable a)
=> a -> a -> a)
-> Cell constr -> Cell constr -> Cell constr
-> Cell constr
map2Cells1 f def x y = runIdentity $ apply2Cells (fmap pure . f) (pure def) x y
map2Cells1' :: HasCell c (Cell constr)
=> (forall a. (constr a,Typeable a)
=> a -> a -> a)
-> c -> c -> c -> c
map2Cells1' f def x y = view (from cell) $ map2Cells f (def^.cell) (x^.cell) (y^.cell)
read2CellsWith :: (forall a. (constr a,Typeable a) => a -> a -> r) -> r -> Cell constr -> Cell constr -> r
read2CellsWith f = read2Cells1With $ onIdentity f
read2CellsWith' :: HasCell c (Cell constr)
=> (forall a. (constr a,Typeable a) => a -> a -> r)
-> r -> c -> c -> r
read2CellsWith' f def x y = read2CellsWith f def (x^.cell) (y^.cell)
read2Cells1With :: Typeable f
=> (forall a. (constr a,Typeable a) => f a -> f a -> r)
-> r -> Cell1 f constr -> Cell1 f constr -> r
read2Cells1With f x = fmap getConst . apply2Cells1 (fmap Const . f) (Const x)
read2Cells1With' :: (HasCell c (Cell1 f constr),Typeable f)
=> (forall a. (constr a,Typeable a) => f a -> f a -> r)
-> r -> c -> c -> r
read2Cells1With' f def x y = read2Cells1With f def (x^.cell) (y^.cell)
read2CellsH :: (forall a b. (constr a,Typeable a,constr b,Typeable b) => a -> b -> r)
-> Cell constr -> Cell constr -> r
read2CellsH f (Cell x) (Cell y) = f (runIdentity x) (runIdentity y)
read2CellsH' :: HasCell c (Cell constr)
=> (forall a b. (constr a,Typeable a,constr b,Typeable b) => a -> b -> r)
-> c -> c -> r
read2CellsH' f x y = read2CellsH f (x^.cell) (y^.cell)
read2Cells1H :: (forall a b. (constr a,Typeable a,constr b,Typeable b) => f a -> f b -> r)
-> Cell1 f constr -> Cell1 f constr -> r
read2Cells1H f (Cell x) (Cell y) = f x y
read2Cells1H' :: (forall a b. (constr a,Typeable a,constr b,Typeable b) => f a -> f b -> r)
-> Cell1 f constr -> Cell1 f constr -> r
read2Cells1H' f x y = read2Cells1H f (x^.cell) (y^.cell)
cell1Equal :: Typeable f
=> (forall a. constr a => f a -> f a -> Bool)
-> Cell1 f constr
-> Cell1 f constr
-> Bool
cell1Equal f = read2Cells1With f False
cell1Equal' :: (HasCell c (Cell1 f constr),Typeable f)
=> (forall a. constr a => f a -> f a -> Bool)
-> c -> c -> Bool
cell1Equal' f x y = cell1Equal f (x^.cell) (y^.cell)
cellEqual :: (forall a. constr a => a -> a -> Bool)
-> Cell constr
-> Cell constr
-> Bool
cellEqual f = read2CellsWith f False
cellEqual' :: HasCell c (Cell constr)
=> (forall a. constr a => a -> a -> Bool)
-> c -> c -> Bool
cellEqual' f x y = cellEqual f (x^.cell) (y^.cell)
cellCompare :: (forall a. constr a => a -> a -> Ordering)
-> Cell constr
-> Cell constr
-> Ordering
cellCompare = cellCompare'
cellCompare' :: HasCell c (Cell constr)
=> (forall a. constr a => a -> a -> Ordering)
-> c -> c -> Ordering
cellCompare' f = cell1Compare' $ onIdentity f
cell1Compare :: (Typeable f)
=> (forall a. constr a => f a -> f a -> Ordering)
-> Cell1 f constr
-> Cell1 f constr
-> Ordering
cell1Compare f x y = read2Cells1With f (x' `compare` y') x y
where
x' = readCell1 typeOf x :: TypeRep
y' = readCell1 typeOf y :: TypeRep
cell1Compare' :: (HasCell c (Cell1 f constr),Typeable f)
=> (forall a. constr a => f a -> f a -> Ordering)
-> c -> c -> Ordering
cell1Compare' f x y = cell1Compare f (x^.cell) (y^.cell)
cellLens :: Functor f => (forall a. constr a => LensLike' f a b) -> LensLike' f (Cell constr) b
cellLens = cellLens'
cellLens' :: (HasCell c (Cell constr), Functor f)
=> (forall a. constr a => LensLike' f a b)
-> LensLike' f c b
cellLens' ln f = traverseCell' (ln f)
cell1Lens :: Functor f => (forall a. constr a => LensLike' f (g a) b) -> LensLike' f (Cell1 g constr) b
cell1Lens = cell1Lens'
cell1Lens' :: (HasCell c (Cell1 g constr), Functor f)
=> (forall a. constr a => LensLike' f (g a) b)
-> LensLike' f c b
cell1Lens' ln f = traverseCell1' (ln f)
arbitraryCell :: Name -> ExpQ
arbitraryCell cl = arbitraryCell' cl []
arbitraryCell' :: Name -> [TypeQ] -> ExpQ
arbitraryCell' cl ts = [e| $(arbitraryInstanceOf' 'Cell cl ts) :: Gen (Cell $(conT cl)) |]
arbitraryInstanceOf :: Name -> Name -> ExpQ
arbitraryInstanceOf cons cl = arbitraryInstanceOf' cons cl []
arbitraryInstanceOf' :: Name -> Name -> [TypeQ] -> ExpQ
arbitraryInstanceOf' cons cl ts = do
ClassI _ is <- reify cl
ts <- sequence ts
let getArg (InstanceD [] (AppT _ t) [])
| t `notElem` ts = return (Just t)
| otherwise = return Nothing
getArg t = do
reportError $ "invalid number of arguments in instance: " ++ pprint t
return Nothing
is' <- catMaybes <$> mapM (fmap (fmap return) . getArg) is
let arbits = [ [e| $(conE cons) <$> $(arb i) |] | i <- is' ]
arb i = sigE [e| arbitrary |] [t| Gen $i |]
when (null is') $ fail $ printf "no instances of '%s' found" (show cl)
[e| oneof $(listE arbits) |]
onIdentity :: (a -> b -> c)
-> Identity a -> Identity b
-> c
onIdentity f (Identity x) (Identity y) = f x y
prop_consistent_equal :: (Eq a,Typeable a) => a -> a -> Property
prop_consistent_equal x y = cellEqual (==) (makeCell' x) (makeCell' y) === (x == y)
where
makeCell' = makeCell :: (Eq a,Typeable a) => a -> Cell Eq
prop_consistent_compare :: (Ord a,Typeable a) => a -> a -> Property
prop_consistent_compare x y = cellCompare compare (makeCell' x) (makeCell' y) === (x `compare` y)
where
makeCell' = makeCell :: (Ord a,Typeable a) => a -> Cell Ord
return []
run_tests :: IO Bool
run_tests = $quickCheckAll