packages feed

ghc-typelits-extra 0.4 → 0.4.1

raw patch · 7 files changed

+257/−130 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- GHC.TypeLits.Extra: instance (GHC.TypeNats.KnownNat x, GHC.TypeNats.KnownNat y, GHC.TypeLits.Extra.FLog x y Data.Type.Equality.~ GHC.TypeLits.Extra.CLog x y) => GHC.TypeLits.KnownNat.KnownNat2 "GHC.TypeLits.Extra.Log" x y
+ GHC.TypeLits.Extra: instance (GHC.TypeNats.KnownNat x, GHC.TypeNats.KnownNat y, GHC.TypeLits.Extra.FLog x y GHC.Types.~ GHC.TypeLits.Extra.CLog x y) => GHC.TypeLits.KnownNat.KnownNat2 "GHC.TypeLits.Extra.Log" x y
+ GHC.TypeLits.Extra.Solver: instance Outputable.Outputable GHC.TypeLits.Extra.Solver.SolverConstraint

Files

CHANGELOG.md view
@@ -1,5 +1,8 @@ # Changelog for the [`ghc-typelits-extra`](http://hackage.haskell.org/package/ghc-typelits-extra) package +# 0.4.1 *November 10 2020*+* Reduce `n <=? Max (n + p) p` to `True`+ # 0.4 *March 9 2020* * `Max` short-circuits on zero, but is stuckness preserving. i.e. `Max (0-1) 0` reduces to `(0-1)` * Reduce inside arithmetic equations. e.g. `1 + a ~ Max 0 a + CLog 2 2`
ghc-typelits-extra.cabal view
@@ -1,5 +1,5 @@ name:                ghc-typelits-extra-version:             0.4+version:             0.4.1 synopsis:            Additional type-level operations on GHC.TypeLits.Nat description:   Additional type-level operations on @GHC.TypeLits.Nat@:
src/GHC/TypeLits/Extra/Solver.hs view
@@ -24,10 +24,9 @@  -- external import Control.Monad.Trans.Maybe (MaybeT (..))-import Data.Either               (lefts) import Data.Maybe                (catMaybes)-import GHC.TcPluginM.Extra       (evByFiat, lookupModule, lookupName,-                                  tracePlugin)+import GHC.TcPluginM.Extra       (evByFiat, lookupModule, lookupName+                                 ,tracePlugin, newWanted)  -- GHC API import FastString (fsLit)@@ -38,10 +37,11 @@ #if MIN_VERSION_ghc(8,6,0) import Plugins    (purePlugin) #endif+import PrelNames  (eqPrimTyConKey, hasKey) import TcEvidence (EvTerm) import TcPluginM  (TcPluginM, tcLookupTyCon, tcPluginTrace) import TcRnTypes  (TcPlugin(..), TcPluginResult (..))-import Type       (Kind, eqType)+import Type       (Kind, eqType, mkTyConApp, splitTyConApp_maybe) import TyCoRep    (Type (..)) import TysWiredIn (typeNatKind, promotedTrueDataCon, promotedFalseDataCon) import TcTypeNats (typeNatLeqTyCon)@@ -54,11 +54,11 @@ #endif  #if MIN_VERSION_ghc(8,10,0)-import Constraint (Ct, ctEvidence, ctEvPred, isWantedCt)+import Constraint (Ct, ctEvidence, ctEvPred, ctLoc, isWantedCt, cc_ev) import Predicate  (EqRel (NomEq), Pred (EqPred), classifyPredType) import Type       (typeKind) #else-import TcRnTypes  (Ct, ctEvidence, ctEvPred, isWantedCt)+import TcRnTypes  (Ct, CtEvidence, ctEvidence, ctEvPred, ctLoc, isWantedCt, cc_ev) import TcType     (typeKind) import Type       (EqRel (NomEq), PredTree (EqPred), classifyPredType) #endif@@ -114,100 +114,129 @@ decideEqualSOP defs givens  _deriveds wanteds = do   -- GHC 7.10.1 puts deriveds with the wanteds, so filter them out   let wanteds' = filter isWantedCt wanteds-  unit_wanteds <- catMaybes <$> mapM (runMaybeT . toNatEquality defs) wanteds'+  unit_wanteds <- catMaybes <$> mapM (runMaybeT . toSolverConstraint defs) wanteds'   case unit_wanteds of     [] -> return (TcPluginOk [] [])     _  -> do #if MIN_VERSION_ghc(8,4,0)-      unit_givens <- catMaybes <$> mapM (runMaybeT . toNatEquality defs) (givens ++ flattenGivens givens)+      unit_givens <- catMaybes <$> mapM (runMaybeT . toSolverConstraint defs) (givens ++ flattenGivens givens) #else-      unit_givens <- catMaybes <$> mapM ((runMaybeT . toNatEquality defs) <=< zonkCt) givens+      unit_givens <- catMaybes <$> mapM ((runMaybeT . toSolverConstraint defs) <=< zonkCt) givens #endif-      sr <- simplifyExtra (unit_givens ++ unit_wanteds)+      sr <- simplifyExtra defs (unit_givens ++ unit_wanteds)       tcPluginTrace "normalised" (ppr sr)       case sr of-        Simplified evs -> return (TcPluginOk (filter (isWantedCt . snd) evs) [])-        Impossible eq  -> return (TcPluginContradiction [fromNatEquality eq])+        Simplified evs new -> return (TcPluginOk (filter (isWantedCt . snd) evs) new)+        Impossible eq  -> return (TcPluginContradiction [fromSolverConstraint eq]) -type NatEquality   = (Ct,ExtraOp,ExtraOp)-type NatInEquality = (Ct,ExtraOp,ExtraOp,Bool)+data SolverConstraint+   = NatEquality Ct ExtraOp ExtraOp Normalised+   | NatInequality Ct ExtraOp ExtraOp Bool Normalised +instance Outputable SolverConstraint where+  ppr (NatEquality ct op1 op2 norm) = text "NatEquality" $$ ppr ct $$ ppr op1 $$ ppr op2 $$ ppr norm+  ppr (NatInequality _ op1 op2 b norm) = text "NatInequality" $$ ppr op1 $$ ppr op2 $$ ppr b $$ ppr norm+ data SimplifyResult-  = Simplified [(EvTerm,Ct)]-  | Impossible (Either NatEquality NatInEquality)+  = Simplified [(EvTerm,Ct)] [Ct]+  | Impossible SolverConstraint  instance Outputable SimplifyResult where-  ppr (Simplified evs) = text "Simplified" $$ ppr evs-  ppr (Impossible eq)  = text "Impossible" <+> ppr eq+  ppr (Simplified evs new) = text "Simplified" $$ text "Solved:" $$ ppr evs $$ text "New:" $$ ppr new+  ppr (Impossible sct)  = text "Impossible" <+> ppr sct -simplifyExtra :: [Either NatEquality NatInEquality] -> TcPluginM SimplifyResult-simplifyExtra eqs = tcPluginTrace "simplifyExtra" (ppr eqs) >> simples [] eqs+simplifyExtra :: ExtraDefs -> [SolverConstraint] -> TcPluginM SimplifyResult+simplifyExtra defs eqs = tcPluginTrace "simplifyExtra" (ppr eqs) >> simples [] [] eqs   where-    simples :: [Maybe (EvTerm, Ct)] -> [Either NatEquality NatInEquality] -> TcPluginM SimplifyResult-    simples evs [] = return (Simplified (catMaybes evs))-    simples evs (eq@(Left (ct,u,v)):eqs') = do+    simples :: [Maybe (EvTerm, Ct)] -> [Ct] -> [SolverConstraint] -> TcPluginM SimplifyResult+    simples evs news [] = return (Simplified (catMaybes evs) news)+    simples evs news (eq@(NatEquality ct u v norm):eqs') = do       ur <- unifyExtra ct u v       tcPluginTrace "unifyExtra result" (ppr ur)       case ur of-        Win  -> simples (((,) <$> evMagic ct <*> pure ct):evs) eqs'-        Lose -> if null evs && null eqs'-                   then return  (Impossible eq)-                   else simples evs eqs'-        Draw -> simples evs eqs'-    simples evs (eq@(Right (ct,u,v,b)):eqs') = do+        Win                          -> simples (((,) <$> evMagic ct <*> pure ct):evs) news eqs'+        Lose | null evs && null eqs' -> return (Impossible eq)+        _ | norm == Normalised && isWantedCt ct -> do+          newCt <- createWantedFromNormalised defs eq+          simples (((,) <$> evMagic ct <*> pure ct):evs) (newCt:news) eqs'+        Lose -> simples evs news eqs'+        Draw -> simples evs news eqs'+    simples evs news (eq@(NatInequality ct u v b norm):eqs') = do       tcPluginTrace "unifyExtra leq result" (ppr (u,v,b))       case (u,v) of         (I i,I j)-          | (i <= j) == b -> simples (((,) <$> evMagic ct <*> pure ct):evs) eqs'+          | (i <= j) == b -> simples (((,) <$> evMagic ct <*> pure ct):evs) news eqs'           | otherwise     -> return  (Impossible eq)         (p, Max x y)-          | b && (p == x || p == y) -> simples (((,) <$> evMagic ct <*> pure ct):evs) eqs'+          | b && (p == x || p == y) -> simples (((,) <$> evMagic ct <*> pure ct):evs) news eqs'          -- transform:  q ~ Max x y => (p <=? q ~ True)         -- to:         (p <=? Max x y) ~ True         -- and try to solve that along with the rest of the eqs'         (p, q@(V _))           | b -> case findMax q eqs of-                   Just m  -> simples evs ((Right (ct,p,m,b)):eqs')-                   Nothing -> simples evs eqs'-        _ -> simples evs eqs'+                   Just m  -> simples evs news (NatInequality ct p m b norm:eqs')+                   Nothing -> simples evs news eqs'+        _ | norm == Normalised && isWantedCt ct -> do+          newCt <- createWantedFromNormalised defs eq+          simples (((,) <$> evMagic ct <*> pure ct):evs) (newCt:news) eqs'+        _ -> simples evs news eqs'      -- look for given constraint with the form: c ~ Max x y-    findMax :: ExtraOp -> [Either NatEquality NatInEquality] -> Maybe ExtraOp-    findMax c = go . lefts+    findMax :: ExtraOp -> [SolverConstraint] -> Maybe ExtraOp+    findMax c = go       where         go [] = Nothing-        go ((ct, a,b@(Max _ _)) :_)+        go ((NatEquality ct a b@(Max _ _) _) :_)           | c == a && not (isWantedCt ct)             = Just b-        go ((ct, a@(Max _ _),b) :_)+        go ((NatEquality ct a@(Max _ _) b _) :_)           | c == b && not (isWantedCt ct)             = Just a         go (_:rest) = go rest   -- Extract the Nat equality constraints-toNatEquality :: ExtraDefs -> Ct -> MaybeT TcPluginM (Either NatEquality NatInEquality)-toNatEquality defs ct = case classifyPredType $ ctEvPred $ ctEvidence ct of+toSolverConstraint :: ExtraDefs -> Ct -> MaybeT TcPluginM SolverConstraint+toSolverConstraint defs ct = case classifyPredType $ ctEvPred $ ctEvidence ct of     EqPred NomEq t1 t2       | isNatKind (typeKind t1) || isNatKind (typeKind t2)-      -> Left <$> ((ct,,) <$> normaliseNat defs t1 <*> normaliseNat defs t2)+      -> do+         (t1', n1) <- normaliseNat defs t1+         (t2', n2) <- normaliseNat defs t2+         pure (NatEquality ct t1' t2' (mergeNormalised n1 n2))       | TyConApp tc [x,y] <- t1       , tc == typeNatLeqTyCon       , TyConApp tc' [] <- t2-      -> if tc' == promotedTrueDataCon-            then Right <$> ((ct,,,True) <$> normaliseNat defs x <*> normaliseNat defs y)-            else if tc' == promotedFalseDataCon-                 then Right <$> ((ct,,,False) <$> normaliseNat defs x <*> normaliseNat defs y)-                 else fail "Nothing"+      -> do+          (x', n1) <- normaliseNat defs x+          (y', n2) <- normaliseNat defs y+          let res | tc' == promotedTrueDataCon  = pure (NatInequality ct x' y' True  (mergeNormalised n1 n2))+                  | tc' == promotedFalseDataCon = pure (NatInequality ct x' y' False (mergeNormalised n1 n2))+                  | otherwise                   = fail "Nothing"+          res     _ -> fail "Nothing"   where     isNatKind :: Kind -> Bool     isNatKind = (`eqType` typeNatKind) -fromNatEquality :: Either NatEquality NatInEquality -> Ct-fromNatEquality (Left (ct, _, _))  = ct-fromNatEquality (Right (ct,_,_,_)) = ct+createWantedFromNormalised :: ExtraDefs -> SolverConstraint -> TcPluginM Ct+createWantedFromNormalised defs sct = do+  let extractCtSides (NatEquality ct t1 t2 _)   = (ct, reifyEOP defs t1, reifyEOP defs t2)+      extractCtSides (NatInequality ct x y b _) = let tc = if b then promotedTrueDataCon else promotedFalseDataCon+                                                      t1 = TyConApp typeNatLeqTyCon [reifyEOP defs x, reifyEOP defs y]+                                                      t2 = TyConApp tc []+                                                    in (ct, t1, t2)+  let (ct, t1, t2) = extractCtSides sct+  newPredTy <- case splitTyConApp_maybe $ ctEvPred $ ctEvidence ct of+    Just (tc, [a, b, _, _]) | tc `hasKey` eqPrimTyConKey -> pure (mkTyConApp tc [a, b, t1, t2])+    _ -> fail "Nothing"+  ev <- newWanted (ctLoc ct) newPredTy+  return (ct { cc_ev = ev })++fromSolverConstraint :: SolverConstraint -> Ct+fromSolverConstraint (NatEquality ct _ _ _)  = ct+fromSolverConstraint (NatInequality ct _ _ _ _) = ct  lookupExtraDefs :: TcPluginM ExtraDefs lookupExtraDefs = do
src/GHC/TypeLits/Extra/Solver/Operations.hs view
@@ -11,6 +11,9 @@ module GHC.TypeLits.Extra.Solver.Operations   ( ExtraOp (..)   , ExtraDefs (..)+  , Normalised (..)+  , NormaliseResult+  , mergeNormalised   , reifyEOP   , mergeMax   , mergeMin@@ -42,6 +45,23 @@ import TyCon      (TyCon) import Type       (Type, TyVar, mkNumLitTy, mkTyConApp, mkTyVarTy) +-- | Indicates whether normalisation has occured+data Normalised = Normalised | Untouched+  deriving Eq++instance Outputable Normalised where+  ppr Normalised = text "Normalised"+  ppr Untouched  = text "Untouched"++mergeNormalised :: Normalised -> Normalised -> Normalised+mergeNormalised Normalised _ = Normalised+mergeNormalised _ Normalised = Normalised+mergeNormalised _ _          = Untouched++-- | A normalise result contains the ExtraOp and a flag that indicates whether any expression+-- | was normalised within the ExtraOp.+type NormaliseResult = (ExtraOp, Normalised)+ data ExtraOp   = I    Integer   | V    TyVar@@ -110,80 +130,80 @@ reifyEOP defs (Exp x y)  = mkTyConApp typeNatExpTyCon  [reifyEOP defs x                                                        ,reifyEOP defs y] -mergeMax :: ExtraDefs -> ExtraOp -> ExtraOp -> ExtraOp-mergeMax _ (I 0) y = y-mergeMax _ x (I 0) = x+mergeMax :: ExtraDefs -> ExtraOp -> ExtraOp -> NormaliseResult+mergeMax _ (I 0) y = (y, Normalised)+mergeMax _ x (I 0) = (x, Normalised) mergeMax defs x y =   let x' = reifyEOP defs x       y' = reifyEOP defs y       z  = fst (runWriter (normaliseNat (mkTyConApp typeNatSubTyCon [y',x']))) #if MIN_VERSION_ghc_typelits_natnormalise(0,7,0)   in  case runWriterT (isNatural z) of-        Just (True , cs) | Set.null cs -> y-        Just (False, cs) | Set.null cs -> x+        Just (True , cs) | Set.null cs -> (y, Normalised)+        Just (False, cs) | Set.null cs -> (x, Normalised) #else   in  case isNatural z of-        Just True  -> y-        Just False -> x+        Just True  -> (y, Normalised)+        Just False -> (x, Normalised) #endif-        _ -> Max x y+        _ -> (Max x y, Untouched) -mergeMin :: ExtraDefs -> ExtraOp -> ExtraOp -> ExtraOp+mergeMin :: ExtraDefs -> ExtraOp -> ExtraOp -> NormaliseResult mergeMin defs x y =   let x' = reifyEOP defs x       y' = reifyEOP defs y       z  = fst (runWriter (normaliseNat (mkTyConApp typeNatSubTyCon [y',x']))) #if MIN_VERSION_ghc_typelits_natnormalise(0,7,0)   in  case runWriterT (isNatural z) of-        Just (True, cs) | Set.null cs -> x-        Just (False,cs) | Set.null cs -> y+        Just (True, cs) | Set.null cs -> (x, Normalised)+        Just (False,cs) | Set.null cs -> (y, Normalised) #else   in  case isNatural z of-        Just True  -> x-        Just False -> y+        Just True  -> (x, Normalised)+        Just False -> (y, Normalised) #endif-        _ -> Min x y+        _ -> (Min x y, Untouched) -mergeDiv :: ExtraOp -> ExtraOp -> Maybe ExtraOp+mergeDiv :: ExtraOp -> ExtraOp -> Maybe NormaliseResult mergeDiv _     (I 0)      = Nothing-mergeDiv (I i) (I j)      = Just (I (div i j))-mergeDiv x y              = Just (Div x y)+mergeDiv (I i) (I j)      = Just (I (div i j), Normalised)+mergeDiv x y              = Just (Div x y, Untouched) -mergeMod :: ExtraOp -> ExtraOp -> Maybe ExtraOp+mergeMod :: ExtraOp -> ExtraOp -> Maybe NormaliseResult mergeMod _     (I 0)      = Nothing-mergeMod (I i) (I j)      = Just (I (mod i j))-mergeMod x y              = Just (Mod x y)+mergeMod (I i) (I j)      = Just (I (mod i j), Normalised)+mergeMod x y              = Just (Mod x y, Untouched) -mergeFLog :: ExtraOp -> ExtraOp -> Maybe ExtraOp+mergeFLog :: ExtraOp -> ExtraOp -> Maybe NormaliseResult mergeFLog (I i) _         | i < 2  = Nothing-mergeFLog i     (Exp j k) | i == j = Just k-mergeFLog (I i) (I j)              = I <$> flogBase i j-mergeFLog x     y                  = Just (FLog x y)+mergeFLog i     (Exp j k) | i == j = Just (k, Normalised)+mergeFLog (I i) (I j)              = fmap (\r -> (I r, Normalised)) (flogBase i j)+mergeFLog x     y                  = Just (FLog x y, Untouched) -mergeCLog :: ExtraOp -> ExtraOp -> Maybe ExtraOp+mergeCLog :: ExtraOp -> ExtraOp -> Maybe NormaliseResult mergeCLog (I i) _         | i < 2  = Nothing-mergeCLog i     (Exp j k) | i == j = Just k-mergeCLog (I i) (I j)              = I <$> clogBase i j-mergeCLog x     y                  = Just (CLog x y)+mergeCLog i     (Exp j k) | i == j = Just (k, Normalised)+mergeCLog (I i) (I j)              = fmap (\r -> (I r, Normalised)) (clogBase i j)+mergeCLog x     y                  = Just (CLog x y, Untouched) -mergeLog :: ExtraOp -> ExtraOp -> Maybe ExtraOp+mergeLog :: ExtraOp -> ExtraOp -> Maybe NormaliseResult mergeLog (I i) _          | i < 2   = Nothing-mergeLog b     (Exp b' y) | b == b' = Just y-mergeLog (I i) (I j)                = I <$> exactLogBase i j-mergeLog x     y                    = Just (Log x y)+mergeLog b     (Exp b' y) | b == b' = Just (y, Normalised)+mergeLog (I i) (I j)                = fmap (\r -> (I r, Normalised)) (exactLogBase i j)+mergeLog x     y                    = Just (Log x y, Untouched) -mergeGCD :: ExtraOp -> ExtraOp -> ExtraOp-mergeGCD (I i) (I j) = I (gcd i j)-mergeGCD x     y     = GCD x y+mergeGCD :: ExtraOp -> ExtraOp -> NormaliseResult+mergeGCD (I i) (I j) = (I (gcd i j), Normalised)+mergeGCD x     y     = (GCD x y, Untouched) -mergeLCM :: ExtraOp -> ExtraOp -> ExtraOp-mergeLCM (I i) (I j) = I (lcm i j)-mergeLCM x     y     = LCM x y+mergeLCM :: ExtraOp -> ExtraOp -> NormaliseResult+mergeLCM (I i) (I j) = (I (lcm i j), Normalised)+mergeLCM x     y     = (LCM x y, Untouched) -mergeExp :: ExtraOp -> ExtraOp -> ExtraOp-mergeExp (I i) (I j)                = I (i^j)-mergeExp b     (Log b' y) | b == b' = y-mergeExp x     y                    = Exp x y+mergeExp :: ExtraOp -> ExtraOp -> NormaliseResult+mergeExp (I i) (I j)                = (I (i^j), Normalised)+mergeExp b     (Log b' y) | b == b' = (y, Normalised)+mergeExp x     y                    = (Exp x y, Untouched)  -- | \x y -> logBase x y, x > 1 && y > 0 flogBase :: Integer -> Integer -> Maybe Integer
src/GHC/TypeLits/Extra/Solver/Unify.hs view
@@ -10,6 +10,7 @@ module GHC.TypeLits.Extra.Solver.Unify   ( ExtraDefs (..)   , UnifyResult (..)+  , NormaliseResult   , normaliseNat   , unifyExtra   )@@ -18,14 +19,13 @@ -- external import Control.Monad.Trans.Class    (lift) import Control.Monad.Trans.Maybe    (MaybeT (..))-import Control.Monad.Trans.Writer.Strict (runWriter)+import Data.Maybe                   (catMaybes) import Data.Function                (on) import GHC.TypeLits.Normalise.Unify (CType (..))-import qualified GHC.TypeLits.Normalise.Unify as Normalise  -- GHC API import Outputable (Outputable (..), ($$), text)-import TcPluginM  (TcPluginM, matchFam, tcPluginTrace)+import TcPluginM  (TcPluginM, tcPluginTrace) import TcTypeNats (typeNatExpTyCon) import Type       (TyVar, coreView) import TyCoRep    (Type (..), TyLit (..))@@ -40,46 +40,65 @@ -- internal import GHC.TypeLits.Extra.Solver.Operations -normaliseNat :: ExtraDefs -> Type -> MaybeT TcPluginM ExtraOp+mergeNormResWith+  :: (ExtraOp -> ExtraOp -> MaybeT TcPluginM NormaliseResult)+  -> MaybeT TcPluginM NormaliseResult+  -> MaybeT TcPluginM NormaliseResult+  -> MaybeT TcPluginM NormaliseResult+mergeNormResWith f x y = do+  (x', n1) <- x+  (y', n2) <- y+  (res, n3) <- f x' y'+  pure (res, n1 `mergeNormalised` n2 `mergeNormalised` n3)+++normaliseNat :: ExtraDefs -> Type -> MaybeT TcPluginM NormaliseResult normaliseNat defs ty | Just ty1 <- coreView ty = normaliseNat defs ty1-normaliseNat _ (TyVarTy v)          = pure (V v)-normaliseNat _ (LitTy (NumTyLit i)) = pure (I i)+normaliseNat _ (TyVarTy v)          = pure (V v, Untouched)+normaliseNat _ (LitTy (NumTyLit i)) = pure (I i, Untouched) normaliseNat defs (TyConApp tc [x,y])-  | tc == maxTyCon defs = mergeMax defs <$> normaliseNat defs x-                                        <*> normaliseNat defs y-  | tc == minTyCon defs = mergeMin defs <$> normaliseNat defs x-                                        <*> normaliseNat defs y-  | tc == divTyCon defs = do x' <- normaliseNat defs x-                             y' <- normaliseNat defs y-                             MaybeT (return (mergeDiv x' y'))-  | tc == modTyCon defs = do x' <- normaliseNat defs x-                             y' <- normaliseNat defs y-                             MaybeT (return (mergeMod x' y'))-  | tc == flogTyCon defs = do x' <- normaliseNat defs x-                              y' <- normaliseNat defs y-                              MaybeT (return (mergeFLog x' y'))-  | tc == clogTyCon defs = do x' <- normaliseNat defs x-                              y' <- normaliseNat defs y-                              MaybeT (return (mergeCLog x' y'))-  | tc == logTyCon defs = do x' <- normaliseNat defs x-                             y' <- normaliseNat defs y-                             MaybeT (return (mergeLog x' y'))-  | tc == gcdTyCon defs = mergeGCD <$> normaliseNat defs x-                                   <*> normaliseNat defs y-  | tc == lcmTyCon defs = mergeLCM <$> normaliseNat defs x-                                   <*> normaliseNat defs y-  | tc == typeNatExpTyCon = mergeExp <$> normaliseNat defs x-                                     <*> normaliseNat defs y+  | tc == maxTyCon defs = mergeNormResWith (\x' y' -> return (mergeMax defs x' y'))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == minTyCon defs = mergeNormResWith (\x' y' -> return (mergeMin defs x' y'))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == divTyCon defs = mergeNormResWith (\x' y' -> MaybeT (return (mergeDiv x' y')))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == modTyCon defs = mergeNormResWith (\x' y' -> MaybeT (return (mergeMod x' y')))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == flogTyCon defs = mergeNormResWith (\x' y' -> MaybeT (return (mergeFLog x' y')))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == clogTyCon defs = mergeNormResWith (\x' y' -> MaybeT (return (mergeCLog x' y')))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == logTyCon defs = mergeNormResWith (\x' y' -> MaybeT (return (mergeLog x' y')))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == gcdTyCon defs = mergeNormResWith (\x' y' -> return (mergeGCD x' y'))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == lcmTyCon defs = mergeNormResWith (\x' y' -> return (mergeLCM x' y'))+                                           (normaliseNat defs x)+                                           (normaliseNat defs y)+  | tc == typeNatExpTyCon = mergeNormResWith (\x' y' -> return (mergeExp x' y'))+                                             (normaliseNat defs x)+                                             (normaliseNat defs y)  normaliseNat defs (TyConApp tc tys) = do-  tys'   <- mapM (fmap (reifyEOP defs) . normaliseNat defs) tys-  tyM    <- lift (matchFam tc tys')-  case tyM of-    Just (_,ty) -> normaliseNat defs ty-    _ -> let q = fst (runWriter (Normalise.normaliseNat (TyConApp tc tys')))-         in  return (C (CType (Normalise.reifySOP q)))+  let mergeExtraOp [] = []+      mergeExtraOp ((Just (op, Normalised), _):xs) = reifyEOP defs op:mergeExtraOp xs+      mergeExtraOp ((_, ty):xs) = ty:mergeExtraOp xs -normaliseNat _ t = return (C (CType t))+  normResults <- lift (sequence (runMaybeT . normaliseNat defs <$> tys))+  let anyNormalised = foldr mergeNormalised Untouched (snd <$> catMaybes normResults)+  let tys' = mergeExtraOp (zip normResults tys)+  pure (C (CType (TyConApp tc tys')), anyNormalised)++normaliseNat _ t = return (C (CType t), Untouched)  -- | Result of comparing two 'SOP' terms, returning a potential substitution -- list under which the two terms are equal.
tests/ErrorTests.hs view
@@ -97,6 +97,9 @@  testFail26 = testFail26' (Proxy @4) (Proxy @6) (Proxy @6) +testFail27 :: Proxy n -> Proxy (n + 2 <=? Max (n + 1) 1) -> Proxy True+testFail27 _ = id+ testFail1Errors =   ["Expected type: Proxy (GCD 6 8) -> Proxy 4"   ,"Actual type: Proxy 4 -> Proxy 4"@@ -214,4 +217,9 @@ testFail26Errors =   ["Could not deduce: Max x y ~ n"   ,"from the context: (x <=? n) ~ 'True"+  ]++testFail27Errors =+  ["Expected type: Proxy ((n + 2) <=? Max (n + 1) 1) -> Proxy 'True"+  ,"Actual type: Proxy 'True -> Proxy 'True"   ]
tests/Main.hs view
@@ -191,6 +191,38 @@   -> Proxy (Max 0 (BitPack a) + CLog 2 2) test52 _ = id +test53+  :: Proxy n+  -> Proxy (1 <=? Max (n + 1) 1)+  -> Proxy True+test53 _ = id++test54+  :: Proxy n+  -> Proxy (n <=? Max (n + 1) 1)+  -> Proxy True+test54 _ = id++test55+  :: Proxy n+  -> Proxy (n + 1 <=? Max (n + 1) 1)+  -> Proxy True+test55 _ = id++test56+  :: Proxy n+  -> Proxy p+  -> Proxy (n <=? Max (n + p) p)+  -> Proxy True+test56 _ _ = id++test57+  :: Proxy n+  -> Proxy p+  -> Proxy (n + 1 <=? Max (n + p + 1) p)+  -> Proxy True+test57 _ _ = id+ main :: IO () main = defaultMain tests @@ -353,6 +385,21 @@     , testCase "forall a . (1 + BitPack a) ~ (Max 0 (BitPack a) + CLog 2 2" $       show (test52 Proxy Proxy) @?=       "Proxy"+    , testCase "forall n . 1 <= Max (n + 1) 1" $+      show (test53 Proxy Proxy) @?=+      "Proxy"+    , testCase "forall n . n <= Max (n + 1) 1" $+      show (test54 Proxy Proxy) @?=+      "Proxy"+    , testCase "forall n . n + 1 <= Max (n + 1) 1" $+      show (test55 Proxy Proxy) @?=+      "Proxy"+    , testCase "forall n p . n <= Max (n + p) p" $+      show (test56 Proxy Proxy Proxy) @?=+      "Proxy"+    , testCase "forall n p . n + 1 <= Max (n + p + 1) p" $+      show (test57 Proxy Proxy Proxy) @?=+      "Proxy"     ]   , testGroup "errors"     [ testCase "GCD 6 8 /~ 4" $ testFail1 `throws` testFail1Errors@@ -381,6 +428,7 @@     , testCase "(z <=? Max x y) /~ True" $ testFail24 `throws` testFail24Errors     , testCase "(x+1 <=? Max x y) /~ True" $ testFail25 `throws` testFail25Errors     , testCase "(x <= n) /=> (Max x y) ~ n" $ testFail26 `throws` testFail26Errors+    , testCase "n + 2 <=? Max (n + 1) 1 /~ True" $ testFail27 `throws` testFail27Errors     ]   ]