packages feed

lambda-calculator-3.0.0: test/Language/Lambda/UntypedSpec.hs

{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}
module Language.Lambda.UntypedSpec where

import RIO
import qualified RIO.Map as Map
import qualified RIO.Text as Text
import Test.Hspec

import Language.Lambda.Untyped
import Language.Lambda.Untyped.HspecUtils

spec :: Spec
spec = do
  describe "evalText" $ do
    it "evaluates simple text" $ do
      eval "x" `shouldBe` Right (Var "x")
      eval "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))
      eval "f y" `shouldBe` Right (App (Var "f") (Var "y"))

    it "reduces simple applications" $
      eval "(\\x .x) y" `shouldBe` Right (Var "y")

    it "reduces applications with nested redexes" $
      eval "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))

  describe "runEvalText" $ do
    let runEvalText' input = fst <$> runEvalText input Map.empty
    
    it "evaluates simple strings" $ do
      runEvalText' "x" `shouldBe` Right (Var "x")
      runEvalText' "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))
      runEvalText' "f y" `shouldBe` Right (App (Var "f") (Var "y"))

    it "reduces simple applications" $
      runEvalText' "(\\x .x) y" `shouldBe` Right (Var "y")

    it "reduces applications with nested redexes" $
      runEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))

  describe "execEvalText" $ do
    let execEvalText' input = execEvalText input Map.empty
    
    it "evaluates simple texts" $ do
      execEvalText' "x" `shouldBe` Right (Var "x")
      execEvalText' "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))
      execEvalText' "f y" `shouldBe` Right (App (Var "f") (Var "y"))

    it "reduces simple applications" $
      execEvalText' "(\\x .x) y" `shouldBe` Right (Var "y")

    it "reduces applications with nested redexes" $
      execEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))

  describe "unsafeExecEvalText" $ do
    let unsafeExecEvalText' input = unsafeExecEvalText input Map.empty
    
    it "evaluates simple texts" $ do
      unsafeExecEvalText' "x" `shouldBe` Var "x"
      unsafeExecEvalText' "\\x. x" `shouldBe` Abs "x" (Var "x")
      unsafeExecEvalText' "f y" `shouldBe` App (Var "f") (Var "y")

    it "reduces simple applications" $
      unsafeExecEvalText' "(\\x .x) y" `shouldBe` Var "y"

    it "reduces applications with nested redexes" $
      unsafeExecEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Abs "x" (Var "x")

  describe "defaultUniques" $ do
    let alphabet = reverse ['a'..'z']
        len = length alphabet
    
    it "starts with plain alphabet" $
      take len defaultUniques `shouldBe` map (`Text.cons` Text.empty) alphabet

    it "adds index afterwards" $
      take len (drop len defaultUniques)
        `shouldBe` map (`Text.cons` Text.singleton '0') alphabet