lamb/test/EvaluationSpec.hs
2026-05-15 21:58:31 -05:00

52 lines
2.1 KiB
Haskell

module EvaluationSpec (spec) where
import Evaluation (beta, subst)
import Parser (Expr (Abstraction, Application, Variable))
import Test.Hspec
spec :: Spec
spec = do
describe "subst" $ do
it "cannot substitute mismatched variables" $
subst (Variable "x") "y" (Variable "z") `shouldBe` Variable "x"
it "can substitute matched variables" $
subst (Variable "x") "x" (Variable "z") `shouldBe` Variable "z"
it "can substitute nested variables" $
subst absWithZ "z" absI `shouldBe` absWithZMaker absI
describe "beta reduction" $ do
-- Normal forms (no redex)
it "returns Nothing for a bare variable" $
beta (Variable "x") `shouldBe` Nothing
it "returns Nothing for a bare abstraction" $
beta absI `shouldBe` Nothing
it "returns Nothing when application has no lambda on left" $
beta (Application (Variable "x") (Variable "y")) `shouldBe` Nothing
-- Basic reductions
it "reduces identity: (λi. i) y → y" $
beta (Application absI (Variable "y"))
`shouldBe` Just (Variable "y")
it "reduces constant function: (λx. z) y → z" $
beta (Application (Abstraction "x" (Variable "z")) (Variable "y"))
`shouldBe` Just (Variable "z")
-- Self-application
it "(λx. x x)(λi. i) → (λi. i)(λi. i)" $
beta (Application selfApp absI)
`shouldBe` Just (Application absI absI)
it "(λi. i)(λi. i) → (λi. i)" $
beta (Application absI absI)
`shouldBe` Just absI
-- Redex not at top level
it "reduces redex in function position: ((λi. i) y) z → y z" $
beta (Application (Application absI (Variable "y")) (Variable "z"))
`shouldBe` Just (Application (Variable "y") (Variable "z"))
it "reduces redex inside lambda body: λz. (λi. i) y → λz. y" $
beta (Abstraction "z" (Application absI (Variable "y")))
`shouldBe` Just (Abstraction "z" (Variable "y"))
where
absWithZMaker z = Abstraction "x" (Application z (Variable "x"))
absWithZ = absWithZMaker (Variable "z")
absI = Abstraction "i" (Variable "i")
selfApp = Abstraction "x" (Application (Variable "x") (Variable "x"))