{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Type.Predicate.Auto (
Auto(..)
, autoTC
, AutoNot
, autoNot
, autoAny, autoNotAll
, AutoProvable
, AutoElem(..)
, AutoAll(..)
) where
import Data.Functor.Identity
import Data.List.NonEmpty (NonEmpty(..))
import Data.Singletons
import Data.Singletons.Sigma
import Data.Type.Equality
import Data.Type.Functor.Product
import Data.Type.Predicate
import Data.Type.Predicate.Logic
import Data.Type.Predicate.Param
import Data.Type.Predicate.Quantification
import Data.Type.Universe
class Auto (p :: Predicate k) (a :: k) where
auto :: p @@ a
autoTC :: forall t a. Auto (TyPred t) a => t a
autoTC = auto @_ @(TyPred t) @a
instance SingI a => Auto Evident a where
auto = sing
instance SingI a => Auto (Not Impossible) a where
auto = ($ sing)
instance Auto (EqualTo a) a where
auto = Refl
instance (Auto p a, Auto q a) => Auto (p &&& q) a where
auto = (auto @_ @p @a, auto @_ @q @a)
instance Auto q a => Auto (p ==> q) a where
auto _ = auto @_ @q @a
data AutoProvable :: Predicate k -> Predicate k
type instance Apply (AutoProvable p) a = p @@ a
instance (Provable p, SingI a) => Auto (AutoProvable p) a where
auto = prove @p @a sing
class AutoElem f (as :: f k) (a :: k) where
autoElem :: Elem f as a
instance {-# OVERLAPPING #-} AutoElem [] (a ': as) a where
autoElem = IZ
instance {-# OVERLAPPING #-} AutoElem [] as a => AutoElem [] (b ': as) a where
autoElem = IS autoElem
instance AutoElem Maybe ('Just a) a where
autoElem = IJust
instance AutoElem (Either j) ('Right a) a where
autoElem = IRight
instance AutoElem NonEmpty (a ':| as) a where
autoElem = NEHead
instance AutoElem [] as a => AutoElem NonEmpty (b ':| as) a where
autoElem = NETail autoElem
instance AutoElem ((,) j) '(w, a) a where
autoElem = ISnd
instance AutoElem Identity ('Identity a) a where
autoElem = IId
instance AutoElem f as a => Auto (In f as) a where
auto = autoElem @f @as @a
class AutoAll f (p :: Predicate k) (as :: f k) where
autoAll :: All f p @@ as
instance AutoAll [] p '[] where
autoAll = WitAll $ \case {}
instance (Auto p a, AutoAll [] p as) => AutoAll [] p (a ': as) where
autoAll = WitAll $ \case
IZ -> auto @_ @p @a
IS i -> runWitAll (autoAll @[] @p @as) i
instance AutoAll Maybe p 'Nothing where
autoAll = WitAll $ \case {}
instance Auto p a => AutoAll Maybe p ('Just a) where
autoAll = WitAll $ \case IJust -> auto @_ @p @a
instance AutoAll (Either j) p ('Left e) where
autoAll = WitAll $ \case {}
instance Auto p a => AutoAll (Either j) p ('Right a) where
autoAll = WitAll $ \case IRight -> auto @_ @p @a
instance (Auto p a, AutoAll [] p as) => AutoAll NonEmpty p (a ':| as) where
autoAll = WitAll $ \case
NEHead -> auto @_ @p @a
NETail i -> runWitAll (autoAll @[] @p @as) i
instance Auto p a => AutoAll ((,) j) p '(w, a) where
autoAll = WitAll $ \case ISnd -> auto @_ @p @a
instance Auto p a => AutoAll Identity p ('Identity a) where
autoAll = WitAll $ \case IId -> auto @_ @p @a
instance AutoAll f p as => Auto (All f p) as where
auto = autoAll @f @p @as
instance SingI a => Auto (NotNull []) (a ': as) where
auto = WitAny IZ sing
instance SingI a => Auto IsJust ('Just a) where
auto = WitAny IJust sing
instance SingI a => Auto IsRight ('Right a) where
auto = WitAny IRight sing
instance SingI a => Auto (NotNull NonEmpty) (a ':| as) where
auto = WitAny NEHead sing
instance SingI a => Auto (NotNull ((,) j)) '(w, a) where
auto = WitAny ISnd sing
instance SingI a => Auto (NotNull Identity) ('Identity a) where
auto = WitAny IId sing
type AutoNot (p :: Predicate k) = Auto (Not p)
autoNot :: forall k (p :: Predicate k) (a :: k). AutoNot p a => Not p @@ a
autoNot = auto @k @(Not p) @a
instance Auto (Found p) (f @@ a) => Auto (Found (PPMap f p)) a where
auto = case auto @_ @(Found p) @(f @@ a) of
i :&: p -> i :&: p
instance Auto (NotFound p) (f @@ a) => Auto (NotFound (PPMap f p)) a where
auto = mapRefuted (\(i :&: p) -> i :&: p)
$ autoNot @_ @(Found p) @(f @@ a)
instance Auto p (f @@ a) => Auto (PMap f p) a where
auto = auto @_ @p @(f @@ a)
instance AutoNot p (f @@ a) => Auto (Not (PMap f p)) a where
auto = autoNot @_ @p @(f @@ a)
autoAny
:: forall f p as a. Auto p a
=> Elem f as a
-> Any f p @@ as
autoAny i = WitAny i (auto @_ @p @a)
instance (SingI as, AutoAll f (Not p) as) => Auto (Not (Any f p)) as where
auto = allNotNone sing $ autoAll @f @(Not p) @as
autoNotAll
:: forall p f as a. (AutoNot p a, SingI as)
=> Elem f as a
-> Not (All f p) @@ as
autoNotAll = anyNotNotAll sing . autoAny
instance (SingI as, AutoAll f (Not (Found p)) as) => Auto (Not (Found (AnyMatch f p))) as where
auto = mapRefuted (\(s :&: WitAny i p) -> WitAny i (s :&: p))
$ auto @_ @(Not (Any f (Found p))) @as
instance SingI as => Auto (TyPred (Rec Sing)) as where
auto = singProd sing
instance SingI as => Auto (TyPred (PMaybe Sing)) as where
auto = singProd sing
instance SingI as => Auto (TyPred (NERec Sing)) as where
auto = singProd sing
instance SingI as => Auto (TyPred (PEither Sing)) as where
auto = singProd sing
instance SingI as => Auto (TyPred (PTup Sing)) as where
auto = singProd sing
instance SingI as => Auto (TyPred (PIdentity Sing)) as where
auto = singProd sing