packages feed

variant-1.0.3: src/tests/EGADT.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module EGADT
   ( testsEGADT
   )
where

import Test.Tasty
import Test.Tasty.QuickCheck as QC

import Data.Kind
import Data.Variant.EGADT

-------------------------------
-- Typed lambda-calculus AST
-------------------------------

data LamF (ast :: Type -> Type) t where
   LamF :: (ast a -> ast b) -> LamF ast (a -> b)

data AppF (ast :: Type -> Type) t where
   AppF :: ast (a -> b) -> ast a -> AppF ast b

data VarF (ast :: Type -> Type) t where
   VarF :: String -> VarF ast Int

type AST a = EGADT '[LamF, AppF, VarF] a

-- replace any variable name with "zz"
renameVar :: AST Int -> AST Int
renameVar (VF (VarF _)) = VF (VarF "zz")
renameVar _             = error "Unhandled case"

-- application of a lambda to a variable: well-typed at `AST Int`
applyLamToVar :: AST Int
applyLamToVar = VF (AppF (VF (LamF renameVar)) (VF (VarF "a")))

-------------------------------
-- Tests
-------------------------------

testsEGADT :: TestTree
testsEGADT = testGroup "EGADT" $
   [ testProperty "VarF: pattern match extracts the variable name" $
        case VF (VarF "a") :: AST Int of
           VF (VarF x) -> x == "a"
           _           -> False

   , testProperty "AppF + LamF: well-typed application is constructible" $
        case applyLamToVar of
           VF (AppF _ _) -> True
           _             -> False
   ]