{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Language.Nominal.Properties.SpecUtilities
where
import qualified Data.List.NonEmpty as NE
import Data.Proxy (Proxy (..))
import System.IO.Unsafe (unsafePerformIO)
import Type.Reflection (Typeable)
import Test.QuickCheck
import Language.Nominal.Abs
import Language.Nominal.Examples.SystemF
import Language.Nominal.Name
import Language.Nominal.Nom
import Language.Nominal.Binder
import Language.Nominal.Unify
import Language.Nominal.Unique
import Language.Nominal.Equivar
myatomnames :: [String]
myatomnames = map show [0 :: Int .. 25]
{-# NOINLINE myUniques #-}
myUniques :: [Unique]
myUniques = unsafePerformIO $ mapM (\_x -> newUnique) myatomnames
myAtoms :: proxy s -> [KAtom s]
myAtoms _ = Atom <$> myUniques
instance {-# OVERLAPPING #-} Arbitrary String where
arbitrary = elements $ map return (['a'..'z']++['A'..'Z'])
instance Arbitrary (KAtom s) where
arbitrary = elements $ myAtoms (Proxy :: Proxy s)
instance Arbitrary a => Arbitrary (KName s a) where
arbitrary = Name <$> arbitrary <*> arbitrary
instance {-# OVERLAPPING #-} Arbitrary (Name String) where
arbitrary = do
atm <- arbitrary
return $ Name (show atm) atm
instance (Typeable s, Swappable t, Swappable a, Arbitrary (KName s t), Arbitrary a) => Arbitrary (KAbs (KName s t) a) where
arbitrary = do
nam <- arbitrary
a <- arbitrary
return $ nam @> a
instance (Typeable s, Swappable a, Arbitrary a) => Arbitrary (KNom s a) where
arbitrary = do
nams <- arbitrary
a <- arbitrary
return $ nams @> a
instance Arbitrary Typ where
arbitrary =
sized arbitrarySizedTyp
arbitrarySizedTyp :: Int -> Gen Typ
arbitrarySizedTyp m =
if m < 2 then
TVar <$> arbitrary
else
oneof [TVar <$> arbitrary
,do
t1 <- arbitrarySizedTyp (m `div` 2)
t2 <- arbitrarySizedTyp (m `div` 2)
return $ t1 :-> t2
,do
t <- arbitrarySizedTyp (m-1)
n <- arbitrary
return $ All (n @> t)
]
instance Arbitrary Trm where
arbitrary =
sized arbitrarySizedTrm
arbitrarySizedTrm :: Int -> Gen Trm
arbitrarySizedTrm m =
if m < 2 then
Var <$> arbitrary
else
oneof [Var <$> arbitrary
,do
t1 <- arbitrarySizedTrm (m `div` 2)
t2 <- arbitrarySizedTrm (m `div` 2)
return $ App t1 t2
,do
t <- arbitrarySizedTrm (m-1)
n <- arbitrary
return $ Lam (n @> t)
,do
t1 <- arbitrarySizedTrm (m `div` 2)
t2 <- arbitrarySizedTyp (m `div` 2)
return $ TApp t1 t2
,do
t <- arbitrarySizedTrm (m-1)
n <- arbitrary
return $ TLam (n @> t)
]
instance Arbitrary a => Arbitrary (NE.NonEmpty a) where
arbitrary = (NE.:|) <$> arbitrary <*> arbitrary
genEvFinMap :: (UnifyPerm a, Eq a, Eq b) => Gen a -> Gen b -> Gen (EvFinMap a b)
genEvFinMap genA genB = evFinMap <$> genB <*> listOf ((,) <$> genA <*> genB)
instance forall a b.
( Arbitrary a
, UnifyPerm a
, Eq a
, Arbitrary b
, Eq b
) => Arbitrary (EvFinMap a b) where
arbitrary = genEvFinMap arbitrary arbitrary
shrink f = [evFinMap b xs | (b, xs) <- shrink $ fromEvFinMap f]