{-# LANGUAGE DataKinds, GADTs, KindSignatures, ScopedTypeVariables, TypeOperators,
TypeApplications, TypeFamilies, TypeFamilyDependencies, FlexibleContexts #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
module Main where
import Data.Proxy
import Data.Type.Equality ((:~:)(..))
import GHC.TypeLits
import Test.Tasty
import Test.Tasty.HUnit
import Unsafe.Coerce (unsafeCoerce)
import TestFunctions
test1 :: forall n . KnownNat n => Proxy n -> Integer
test1 _ = natVal (Proxy :: Proxy n) + natVal (Proxy :: Proxy (n+2))
test2 :: forall n . KnownNat n => Proxy n -> Integer
test2 _ = natVal (Proxy :: Proxy (n*3))
test3 :: forall n m . (KnownNat n, KnownNat m) => Proxy n -> Proxy m -> Integer
test3 _ _ = natVal (Proxy :: Proxy (n+m))
test4 :: forall n m . (KnownNat n, KnownNat m) => Proxy n -> Proxy m -> Integer
test4 _ _ = natVal (Proxy :: Proxy (n*m))
test5 :: forall n m . (KnownNat n, KnownNat m) => Proxy n -> Proxy m -> Integer
test5 _ _ = natVal (Proxy :: Proxy (n^m))
test6 :: forall n m . (KnownNat n, KnownNat m) => Proxy n -> Proxy m -> Integer
test6 _ _ = natVal (Proxy :: Proxy ((n^m)+(n*m)))
test7 :: forall n m . (KnownNat m, KnownNat n) => Proxy n -> Proxy m -> Integer
test7 _ _ = natVal (Proxy :: Proxy (Max n m + 1))
test8 :: forall n m . (KnownNat (Min n m)) => Proxy n -> Proxy m -> Integer
test8 _ _ = natVal (Proxy :: Proxy (Min n m + 1))
test9 :: forall n m . (KnownNat m, KnownNat n, n <= m) => Proxy m -> Proxy n -> Integer
test9 _ _ = natVal (Proxy :: Proxy (m-n))
test10 :: forall (n :: Nat) m . (KnownNat m) => Proxy m -> Proxy n -> Integer
test10 _ _ = natVal (Proxy :: Proxy (m-n+n))
test11 :: forall m . (KnownNat m) => Proxy m -> Integer
test11 _ = natVal (Proxy @ (m*m))
test12 :: forall m . (KnownNat (m+1)) => Proxy m -> Integer
test12 = natVal
test13 :: forall m . (KnownNat (m+3)) => Proxy m -> Integer
test13 = natVal
test14 :: forall m . (KnownNat (4+m)) => Proxy (7+m) -> Integer
test14 = natVal
type family Foo (m :: Nat) = (result :: Nat) | result -> m
fakeFooEvidence :: 1 :~: Foo 1
fakeFooEvidence = unsafeCoerce Refl
test15 :: KnownNat (4 + Foo 1) => Proxy (Foo 1) -> Proxy (4 + Foo 1) -> Integer
test15 _ _ = natVal (Proxy @ (Foo 1 + 7))
test16 :: KnownNat (4 + Foo 1 + Foo 1) => Proxy (Foo 1) -> Proxy (4 + Foo 1 + Foo 1) -> Integer
test16 _ _ = natVal (Proxy @ (Foo 1 + 7 + Foo 1))
test17 :: KnownNat (4 + 2 * Foo 1 + Foo 1) => Proxy (Foo 1) -> Proxy (4 + 2 * Foo 1 + Foo 1) -> Integer
test17 _ _ = natVal (Proxy @ (2 * Foo 1 + 7 + Foo 1))
data SNat :: Nat -> * where
SNat :: KnownNat n => SNat n
instance Show (SNat n) where
show s@SNat = show (natVal s)
addSNat :: SNat a -> SNat b -> SNat (a + b)
addSNat SNat SNat = SNat
mulSNat :: SNat a -> SNat b -> SNat (a * b)
mulSNat SNat SNat = SNat
expSNat :: SNat a -> SNat b -> SNat (a ^ b)
expSNat SNat SNat = SNat
subSNat :: (b <= a) => SNat a -> SNat b -> SNat (a - b)
subSNat SNat SNat = SNat
test18 :: SNat (a+1) -> SNat a -> SNat 1
test18 = subSNat
test19 :: SNat (a+b) -> SNat b -> SNat a
test19 = subSNat
test20 :: forall a . (KnownNat (3 * a - a)) => Proxy a -> Integer
test20 _ = natVal (Proxy @ (2 * a))
tests :: TestTree
tests = testGroup "ghc-typelits-natnormalise"
[ testGroup "Basic functionality"
[ testCase "KnownNat 4 + KnownNat 6 ~ 10" $
show (test1 (Proxy @ 4)) @?=
"10"
, testCase "KnownNat 4 * KnownNat 3 ~ 12" $
show (test2 (Proxy @ 4)) @?=
"12"
, testCase "KnownNat 2 + KnownNat 7 ~ 9" $
show (test3 (Proxy @ 2) (Proxy @ 7)) @?=
"9"
, testCase "KnownNat 2 * KnownNat 7 ~ 14" $
show (test4 (Proxy @ 2) (Proxy @ 7)) @?=
"14"
, testCase "KnownNat 2 ^ KnownNat 7 ~ 128" $
show (test5 (Proxy @ 2) (Proxy @ 7)) @?=
"128"
, testCase "KnownNat 3 ^ KnownNat 7 ~ 2187" $
show (test5 (Proxy @ 3) (Proxy @ 7)) @?=
"2187"
, testCase "(KnownNat 2 ^ KnownNat 7) + (KnownNat 2 * KnownNat 7) ~ 142" $
show (test6 (Proxy @ 2) (Proxy @ 7)) @?=
"142"
, testCase "KnownNat (Max 7 5 + 1) ~ 8" $
show (test7 (Proxy @ 7) (Proxy @ 5)) @?=
"8"
, testCase "KnownNat (Min 7 5 + 1) ~ 6" $
show (test8 (Proxy @ 7) (Proxy @ 5)) @?=
"6"
, testCase "KnownNat (7 - 5) ~ 2" $
show (test9 (Proxy @ 7) (Proxy @ 5)) @?=
"2"
],
testGroup "Implications"
[ testCase "KnownNat m => KnownNat (m*m); @ 5" $
show (test11 (Proxy @ 5)) @?=
"25"
, testCase "KnownNat (m+1) => KnownNat m; @ m ~ 5" $
show (test12 (Proxy @ 5)) @?=
"5"
, testCase "KnownNat (m+1) => KnownNat m; @ m ~ 0" $
show (test12 (Proxy @ 0)) @?=
"0"
, testCase "KnownNat (m+3) => KnownNat m; @ m ~ 0" $
show (test13 (Proxy @ 0)) @?=
"0"
, testCase "KnownNat (4+m) => KnownNat (7+m); @ m ~ 1" $
show (test14 (Proxy @ 8)) @?=
"8"
, testCase "KnownNat (4 + Foo 1) => KnownNat (Foo 1 + 7); @ Foo 1 ~ 1" $
(case fakeFooEvidence of
Refl -> show $ test15 (Proxy @ (Foo 1)) (Proxy @ (4 + Foo 1))) @?=
"8"
, testCase "KnownNat (4 + Foo 1 + Foo 1) => KnownNat (Foo 1 + 7 + Foo 1); @ Foo 1 ~ 1" $
(case fakeFooEvidence of
Refl -> show $ test16 (Proxy @ (Foo 1)) (Proxy @ (4 + Foo 1 + Foo 1))) @?=
"9"
, testCase "KnownNat (4 + 2 * Foo 1 + Foo 1) => KnownNat (2 * Foo 1 + 7 + Foo 1); @ Foo 1 ~ 1" $
(case fakeFooEvidence of
Refl -> show $ test17 (Proxy @ (Foo 1)) (Proxy @ (4 + 2 * Foo 1 + Foo 1))) @?=
"10"
, testCase "KnownNat (3 * a - a) => KnownNat (2 * a); @ a ~ 4" $
show (test20 (Proxy @ 4)) @?=
"8"
],
testGroup "Normalisation"
[ testCase "KnownNat (m-n+n) ~ KnownNat m" $
show (test10 (Proxy @ 12) (Proxy @8)) @?=
"12"
, testCase "SNat (a+1) - SNat a = SNat 1" $
show (test18 (SNat @ 11) (SNat @10)) @?=
"1"
, testCase "SNat (a+b) - SNat b = SNat a" $
show (test19 (SNat @ 16) (SNat @10)) @?=
"6"
]
]
main :: IO ()
main = defaultMain tests