lambda-cube-0.3.0.0: test/LambdaCube/SystemFwTest.hs
{-# LANGUAGE QuasiQuotes #-}
module LambdaCube.SystemFwTest where
import qualified Control.Exception
import Control.Monad (forM_, void)
import qualified Data.Text as Text
import LambdaCube.SystemFw
import LambdaCube.SystemFwTestExample
import LambdaCube.TestUtil
import Test.Hspec
import Test.Tasty
import Test.Tasty.Hspec (testSpec)
newtype TestLCType = TestLCType LCType
deriving newtype (Eq)
instance Show TestLCType where
show (TestLCType ty) = Text.unpack $ prettyUnnamedType ty
newtype TestLCTerm = TestLCTerm LCTerm
deriving newtype (Eq)
instance Show TestLCTerm where
show (TestLCTerm tm) = Text.unpack $ prettyUnnamedTerm tm
tests :: IO TestTree
tests = testSpec "SystemFw tests" spec
spec :: Spec
spec = do
describe "SystemFw infer" inferSpec
describe "SystemFw evaluate" evaluateSpec
describe "SystemFw normalize" normalizeSpec
inferSpec :: SpecWith ()
inferSpec = forM_ inferSpecCases $ \(mkTitle, extTm, extTy) -> do
let
tm = elaborate extTm
ty = elaborateType [] extTy
it (mkTitle tm ty) $ do
TestLCType (infer tm) `shouldBe` TestLCType (reduceType ty)
inferSpecCases :: [(LCTerm -> LCType -> String, ExtLCTerm, ExtLCType)]
inferSpecCases =
[ ( const2 "infer lcBaseId should be lcBaseArr"
, lcBaseId
, lcBaseArr
)
, ( makeDefaultInferTitle
, [qTerm| \x : # . $lcBaseArrId $lcBaseId x |]
, lcBaseArr
)
, ( makeDefaultInferTitle
, [qTerm| \x : $lcBaseArr . \y : $lcBaseArr . \z : # . x (y z) |]
, [qType| $lcBaseArr -> $lcBaseArr -> $lcBaseArr |]
)
, ( makeDefaultInferTitle
, [qTerm| \abc : # . (\fdd : $lcBaseArr . fdd abc) |]
, [qType| # -> $lcBaseArr -> # |]
)
, ( const2 "infer lcId should be (! a : * , a -> a)"
, lcId
, [qType| ! a : * , a -> a |]
)
, ( const2 "infer pCN3 should be pCNTy"
, lcCN3
, lcCNTy
)
, ( const2 "infer lcCNSucc should be (lcCNTy -> lcCNTy)"
, [qTerm| $lcCNSucc |]
, [qType| $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer lcCNAdd should be (lcCNTy -> lcCNTy -> lcCNTy)"
, lcCNAdd
, [qType| $lcCNTy -> $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer (lcCNAdd lcCN1 lcCN2) should be lcCNTy"
, [qTerm| $lcCNAdd $lcCN1 $lcCN2 |]
, [qType| $lcCNTy |]
)
, ( const2 "infer lcCNMul should be (lcCNTy -> lcCNTy -> lcCNTy)"
, lcCNMul
, [qType| $lcCNTy -> $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer (lcCNMul lcCN0) should be (lcCNTy -> lcCNTy)"
, [qTerm| $lcCNMul $lcCN0 |]
, [qType| $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer lcCNPred should be (lcCNTy -> lcCNTy)"
, [qTerm| $lcCNPred |]
, [qType| $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer lcCNPredDef should be (lcCNTy -> lcCNTy -> lcCNTy)"
, [qTerm| $lcCNPredDef |]
, [qType| $lcCNTy -> $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer lcCNMinus should be (lcCNTy -> lcCNTy -> lcCNTy)"
, [qTerm| $lcCNMinus |]
, [qType| $lcCNTy -> $lcCNTy -> $lcCNTy |]
)
, ( const2 "infer lcCNIs0 should be (lcCNTy -> lcCBTy)"
, [qTerm| $lcCNIs0 |]
, [qType| $lcCNTy -> $lcCBTy |]
)
, ( const2 "infer lcCLNil should be (!e : * , lcCLTy e)"
, [qTerm| $lcCLNil |]
, [qType| !e : * , $lcCLTy e |]
)
, ( const2 "infer lcCLCons should be (!e : * , e -> lcCLTy e -> lcCLTy e)"
, [qTerm| $lcCLCons |]
, [qType| !e : * , e -> $lcCLTy e -> $lcCLTy e |]
)
, ( const2 "infer lcCL_CN_0_1_2 should be (lcCLTy lcCNTy)"
, [qTerm| $lcCL_CN_0_1_2 |]
, [qType| $lcCLTy $lcCNTy |]
)
, ( const2 "infer lcCLHeadDef should be (!e : * , e -> lcCLTy e -> e)"
, [qTerm| $lcCLHeadDef |]
, [qType| !e : * , e -> $lcCLTy e -> e |]
)
, ( const2 "infer lcCLTail should be (!e : * , lcCLTy e -> lcCLTy e)"
, [qTerm| $lcCLTail |]
, [qType| !e : * , $lcCLTy e -> $lcCLTy e |]
)
, ( const2 "infer lcCLTailDef should be (!e : * , lcCLTy e -> lcCLTy e -> lcCLTy e)"
, [qTerm| $lcCLTailDef |]
, [qType| !e : * , $lcCLTy e -> $lcCLTy e -> $lcCLTy e |]
)
]
evaluateSpec :: SpecWith ()
evaluateSpec = forM_ evaluateSpecCases $ \(mkTitle, extTm, extResTm) -> do
let
tm = elaborate extTm
resTm = elaborate extResTm
it (mkTitle tm resTm) $ do
void . Control.Exception.evaluate $ infer tm
void . Control.Exception.evaluate $ infer resTm
TestLCTerm (liftLCValue (evaluate tm)) `shouldBe` TestLCTerm (liftLCValue (evaluate resTm))
evaluateSpecCases :: [(LCTerm -> LCTerm -> String, ExtLCTerm, ExtLCTerm)]
evaluateSpecCases =
[ ( makeDefaultEvaluateTitle
, [qTerm| (\abc : $lcBaseArr . (\fdd : $lcBaseArr -> $lcBaseArr . fdd abc)) $lcBaseId |]
, [qTerm| \fdd : $lcBaseArr -> $lcBaseArr . fdd $lcBaseId |]
)
, ( const2 "evaluate (lcBaseArrId lcBaseId) should be lcBaseId"
, [qTerm| $lcBaseArrId $lcBaseId |]
, lcBaseId
)
, ( const2 "evaluate (lcBaseArrId (lcBaseArrId lcBaseId)) should be lcBaseId"
, [qTerm| $lcBaseArrId ($lcBaseArrId $lcBaseId) |]
, lcBaseId
)
, ( const2 "evaluate (lcCNAdd lcCN1 lcCN2) should be lcCN3 with unnormalized parts"
, [qTerm| $lcCNAdd $lcCN1 $lcCN2 |]
, [qTerm| @\r : * . \s : r -> r . \z : r . $lcCN1 @r s ($lcCN2 @r s z) |]
)
, ( const2 "evaluate (lcCNSucc lcCN1) should be lcCN2 with unnormalized parts"
, [qTerm| $lcCNSucc $lcCN1 |]
, [qTerm| @\r : * . \s : r -> r . \z : r . s ($lcCN1 @r s z) |]
)
, ( const2 "evaluate (lcCNPredDef lcCN5 lcCN1) should be lcCN0"
, [qTerm| $lcCNPredDef $lcCN5 $lcCN1 |]
, [qTerm| $lcCN0 |]
)
, ( const2 "evaluate (lcCNPredDef lcCN5 lcCN0) should be lcCN5"
, [qTerm| $lcCNPredDef $lcCN5 $lcCN0 |]
, [qTerm| $lcCN5 |]
)
, ( const2 "evaluate (lcCNIs0 lcCN0) should be lcCBTrue"
, [qTerm| $lcCNIs0 $lcCN0 |]
, [qTerm| $lcCBTrue |]
)
, ( const2 "evaluate (lcCNIs0 lcCN2) should be lcCBFalse"
, [qTerm| $lcCNIs0 $lcCN2 |]
, [qTerm| $lcCBFalse |]
)
, ( const2 "evaluate (lcCLHeadDef @lcCNTy lcCN3 lcCL_CN_0_1_2) should be lcCN0"
, [qTerm| $lcCLHeadDef @$lcCNTy $lcCN3 $lcCL_CN_0_1_2 |]
, [qTerm| $lcCN0 |]
)
, ( const2 "evaluate (lcCLTailDef lcCL_CN_0_1_2 (lcCLTailDef lcCL_CN_0_1_2 lcCL_CN_0)) should be lcCL_CN_0_1_2"
, [qTerm| $lcCLTailDef @$lcCNTy $lcCL_CN_0_1_2 ($lcCLTailDef @$lcCNTy $lcCL_CN_0_1_2 $lcCL_CN_0) |]
, [qTerm| $lcCL_CN_0_1_2 |]
)
]
normalizeSpec :: SpecWith ()
normalizeSpec = forM_ normalizeSpecCases $ \(mkTitle, extTm, extResTm) -> do
let
tm = elaborate extTm
resTm = elaborate extResTm
it (mkTitle tm resTm) $ do
void . Control.Exception.evaluate $ infer tm
void . Control.Exception.evaluate $ infer resTm
TestLCTerm (liftLCNormal (normalize tm)) `shouldBe` TestLCTerm (liftLCNormal (normalize resTm))
normalizeSpecCases :: [(LCTerm -> LCTerm -> String, ExtLCTerm, ExtLCTerm)]
normalizeSpecCases =
[ ( makeDefaultNormalizeTitle
, [qTerm| (\abc : $lcBaseArr . (\fdd : $lcBaseArr -> $lcBaseArr . fdd abc)) $lcBaseId |]
, [qTerm| \fdd : $lcBaseArr -> $lcBaseArr . fdd $lcBaseId |]
)
, ( const2 "normalize (lcBaseArrId lcBaseId) should be lcBaseId"
, [qTerm| $lcBaseArrId $lcBaseId |]
, lcBaseId
)
, ( const2 "normalize (lcBaseArrId (lcBaseArrId lcBaseId)) should be lcBaseId"
, [qTerm| $lcBaseArrId ($lcBaseArrId $lcBaseId) |]
, lcBaseId
)
, ( const2 "normalize (lcCNAdd lcCN1 lcCN2) should be lcCN3"
, [qTerm| $lcCNAdd $lcCN0 $lcCN1 |]
, lcCN1
)
, ( const2 "normalize (lcCN4 lcBaseId) should be lcBaseId"
, [qTerm| $lcCN4 @# $lcBaseId |]
, lcBaseId
)
, ( const2 "normalize (lcCNPred lcCN4) should be lcCN3"
, [qTerm| $lcCNPred $lcCN4 |]
, lcCN3
)
, ( const2 "normalize (lcCNMinus lcCN5 lcCN3) should be lcCN2"
, [qTerm| $lcCNMinus $lcCN5 $lcCN3 |]
, lcCN2
)
, ( const2 "normalize (lcCNIs0 lcCN0) should be lcCBTrue"
, [qTerm| $lcCNIs0 $lcCN0 |]
, [qTerm| $lcCBTrue |]
)
, ( const2 "normalize (lcCNIs0 lcCN2) should be lcCBFalse"
, [qTerm| $lcCNIs0 $lcCN2 |]
, [qTerm| $lcCBFalse |]
)
, ( const2 "normalize (lcCLHeadDef lcCN3 lcCL_CN_0_1_2) should be lcCN0"
, [qTerm| $lcCLHeadDef @$lcCNTy $lcCN3 $lcCL_CN_0_1_2 |]
, [qTerm| $lcCN0 |]
)
, ( const2 "normalize (lcCLHeadDef lcCN3 (lcCLTail lcCL_CN_0_1_2)) should be lcCN1"
, [qTerm| $lcCLHeadDef @$lcCNTy $lcCN3 ($lcCLTail @$lcCNTy $lcCL_CN_0_1_2) |]
, [qTerm| $lcCN1 |]
)
, ( const2 "normalize (lcCLHeadDef lcCN3 (lcCLTail (lcCLTail lcCL_CN_0_1_2))) should be lcCN2"
, [qTerm| $lcCLHeadDef @$lcCNTy $lcCN3 ($lcCLTail @$lcCNTy ($lcCLTail @$lcCNTy $lcCL_CN_0_1_2)) |]
, [qTerm| $lcCN2 |]
)
, ( const2 "normalize (lcCLTail (lcCLTail (lcCLTail lcCL_CN_0_1_2))) should be lcCLNil"
, [qTerm| $lcCLTail @$lcCNTy ($lcCLTail @$lcCNTy ($lcCLTail @$lcCNTy $lcCL_CN_0_1_2)) |]
, [qTerm| $lcCLNil @$lcCNTy |]
)
, ( const2 "normalize (lcCLTailDef lcCL_CN_0_1_2 lcCL_CN_0) should be lcCLNil"
, [qTerm| $lcCLTailDef @$lcCNTy $lcCL_CN_0_1_2 $lcCL_CN_0 |]
, [qTerm| $lcCLNil @$lcCNTy |]
)
, ( const2 "normalize (lcCLTailDef lcCL_CN_0_1_2 (lcCLTailDef lcCL_CN_0_1_2 lcCL_CN_0)) should be lcCL_CN_0_1_2"
, [qTerm| $lcCLTailDef @$lcCNTy $lcCL_CN_0_1_2 ($lcCLTailDef @$lcCNTy $lcCL_CN_0_1_2 $lcCL_CN_0) |]
, [qTerm| $lcCL_CN_0_1_2 |]
)
]
makeDefaultInferTitle :: LCTerm -> LCType -> String
makeDefaultInferTitle tm ty =
makeDefaultTitle
"infer"
(prettyShowUnnamedTerm tm)
(prettyShowUnnamedType ty)
makeDefaultEvaluateTitle :: LCTerm -> LCTerm -> String
makeDefaultEvaluateTitle tm resTm =
makeDefaultTitle
"evaluate"
(prettyShowUnnamedTerm tm)
(prettyShowUnnamedTerm resTm)
makeDefaultNormalizeTitle :: LCTerm -> LCTerm -> String
makeDefaultNormalizeTitle tm resTm =
makeDefaultTitle
"normalize"
(prettyShowUnnamedTerm tm)
(prettyShowUnnamedTerm resTm)