Fakultas Ilmu Komputer UI

Commit 435251b3 authored by Sean Gillespie's avatar Sean Gillespie
Browse files

Refactor based on static analysis

parent 6cc049ac
...@@ -5,105 +5,104 @@ import Test.Hspec ...@@ -5,105 +5,104 @@ import Test.Hspec
import Language.Lambda.HspecUtils import Language.Lambda.HspecUtils
spec :: Spec spec :: Spec
spec = do spec = describe "Bool" $ do
describe "Bool" $ do -- Bool is the definition of Booleans. We represent bools
-- Bool is the definition of Booleans. We represent bools -- using Church Encodings:
-- using Church Encodings: --
-- true: \t f. t
-- false: \t f. f
describe "and" $ do
-- The function and takes two Bools and returns true
-- iff both arguments are true
--
-- and(true, true) = true
-- and(false, true) = false
-- and(true, false) = false
-- and(false, false) = false
-- --
-- true: \t f. t -- and is defined by
-- false: \t f. f -- and = \x y. x y x
describe "and" $ do it "true and true = true" $
-- The function and takes two Bools and returns true "(\\x y. x y x) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"
-- iff both arguments are true
-- it "true and false = false" $
-- and(true, true) = true "(\\x y. x y x) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. f"
-- and(false, true) = false
-- and(true, false) = false
-- and(false, false) = false
--
-- and is defined by
-- and = \x y. x y x
it "true and true = true" $ do
"(\\x y. x y x) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"
it "true and false = false" $ do
"(\\x y. x y x) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. f"
it "false and true = false" $ do
"(\\x y. x y x) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. f"
it "false and false = false" $ do
"(\\x y. x y x) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"
it "false and p = false" $ do
"(\\x y. x y x) (\\t f. f) p" `shouldEvalTo` "\\t f. f"
it "true and p = false" $ do
"(\\x y. x y x) (\\t f. t) p" `shouldEvalTo` "p"
describe "or" $ do
-- or takes two Bools and returns true iff either argument is true
--
-- or(true, true) = true
-- or(true, false) = true
-- or(false, true) = true
-- or(false, false) = false
--
-- or is defined by
-- or = \x y. x x y
it "true or true = true" $ do
"(\\x y. x x y) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"
it "true or false = true" $ do it "false and true = false" $
"(\\x y. x x y) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. t" "(\\x y. x y x) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. f"
it "false or true = true" $ do it "false and false = false" $
"(\\x y. x x y) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. t" "(\\x y. x y x) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"
it "false or false = false" $ do it "false and p = false" $
"(\\x y. x x y) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f" "(\\x y. x y x) (\\t f. f) p" `shouldEvalTo` "\\t f. f"
it "true or p = true" $ do it "true and p = false" $
"(\\x y. x x y) (\\t f. t) p" `shouldEvalTo` "\\t f. t" "(\\x y. x y x) (\\t f. t) p" `shouldEvalTo` "p"
it "false or p = p" $ do describe "or" $ do
"(\\x y. x x y) (\\t f. f) p" `shouldEvalTo` "p" -- or takes two Bools and returns true iff either argument is true
--
-- or(true, true) = true
describe "not" $ do -- or(true, false) = true
-- not takes a Bool and returns its opposite value -- or(false, true) = true
-- -- or(false, false) = false
-- not(true) = false --
-- not(false) = true -- or is defined by
-- -- or = \x y. x x y
-- not is defined by it "true or true = true" $
-- not = \x. x (\t f. f) (\t f. t) "(\\x y. x x y) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"
it "not true = false" $ do
"(\\x. x (\\t f. f) (\\t f. t)) \\t f. t" `shouldEvalTo` "\\t f. f" it "true or false = true" $
"(\\x y. x x y) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. t"
it "not false = true"$ do
"(\\x. x (\\t f. f) (\\t f. t)) \\t f. f" `shouldEvalTo` "\\t f. t" it "false or true = true" $
"(\\x y. x x y) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. t"
describe "if" $ do
-- if takes a Bool and two values. If returns the first value it "false or false = false" $
-- if the Bool is true, and the second otherwise. In other words, "(\\x y. x x y) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"
-- if p x y = if p then x else y
-- it "true or p = true" $
-- if(true, x, y) = x "(\\x y. x x y) (\\t f. t) p" `shouldEvalTo` "\\t f. t"
-- if(false, x, y) = y
-- it "false or p = p" $
-- if is defined by "(\\x y. x x y) (\\t f. f) p" `shouldEvalTo` "p"
-- if = \p x y. p x y
it "if true 0 1 = 0" $ do
"(\\p x y. p x y) (\\t f. t) (\\f x. x) (\\f x. f x)" describe "not" $ do
`shouldEvalTo` "\\f x. x" -- not takes a Bool and returns its opposite value
--
it "if false 0 1 = 1" $ do -- not(true) = false
"(\\p x y. p x y) (\\t f. f) (\\f x. x) (\\f x. f x)" -- not(false) = true
`shouldEvalTo` "\\f x. f x" --
-- not is defined by
it "it true p q = p" $ do -- not = \x. x (\t f. f) (\t f. t)
"(\\p x y. p x y) (\\t f. t) p q" `shouldEvalTo` "p" it "not true = false" $
"(\\x. x (\\t f. f) (\\t f. t)) \\t f. t" `shouldEvalTo` "\\t f. f"
it "it false p q = q" $ do
"(\\p x y. p x y) (\\t f. f) p q" `shouldEvalTo` "q" it "not false = true" $
"(\\x. x (\\t f. f) (\\t f. t)) \\t f. f" `shouldEvalTo` "\\t f. t"
describe "if" $ do
-- if takes a Bool and two values. If returns the first value
-- if the Bool is true, and the second otherwise. In other words,
-- if p x y = if p then x else y
--
-- if(true, x, y) = x
-- if(false, x, y) = y
--
-- if is defined by
-- if = \p x y. p x y
it "if true 0 1 = 0" $
"(\\p x y. p x y) (\\t f. t) (\\f x. x) (\\f x. f x)"
`shouldEvalTo` "\\f x. x"
it "if false 0 1 = 1" $
"(\\p x y. p x y) (\\t f. f) (\\f x. x) (\\f x. f x)"
`shouldEvalTo` "\\f x. f x"
it "it true p q = p" $
"(\\p x y. p x y) (\\t f. t) p q" `shouldEvalTo` "p"
it "it false p q = q" $
"(\\p x y. p x y) (\\t f. f) p q" `shouldEvalTo` "q"
...@@ -5,99 +5,98 @@ import Test.Hspec ...@@ -5,99 +5,98 @@ import Test.Hspec
import Language.Lambda.HspecUtils import Language.Lambda.HspecUtils
spec :: Spec spec :: Spec
spec = do spec = describe "Nat" $ do
describe "Nat" $ do -- Nat is the definition of natural numbers. More precisely, Nat
-- Nat is the definition of natural numbers. More precisely, Nat -- is the set of nonnegative integers. We represent nats using
-- is the set of nonnegative integers. We represent nats using -- Church Encodings:
-- Church Encodings: --
-- 0: \f x. x
-- 1: \f x. f x
-- 2: \f x. f (f x)
-- ...and so on
describe "successor" $ do
-- successor is a function that adds 1
-- succ(0) = 1
-- succ(1) = 2
-- ... and so forth
-- --
-- 0: \f x. x -- successor is defined by
-- 1: \f x. f x -- succ = \n f x. f (n f x)
-- 2: \f x. f (f x) it "succ 0 = 1" $
-- ...and so on "(\\n f x. f (n f x)) (\\f x. x)" `shouldEvalTo` "\\f x. f x"
describe "successor" $ do it "succ 1 = 2" $
-- successor is a function that adds 1 "(\\n f x. f (n f x)) (\\f x. f x)" `shouldEvalTo` "\\f x. f (f x)"
-- succ(0) = 1
-- succ(1) = 2 describe "add" $ do
-- ... and so forth -- add(m, n) = m + n
-- --
-- successor is defined by -- It is defined by applying successor m times on n:
-- succ = \n f x. f (n f x) -- add = \m n f x. m f (n f x)
it "succ 0 = 1" $ do it "add 0 2 = 2" $
"(\\n f x. f (n f x)) (\\f x. x)" `shouldEvalTo` "\\f x. f x" "(\\m n f x. m f (n f x)) (\\f x. x) (\\f x. f (f x))"
`shouldEvalTo` "\\f x. f (f x)"
it "succ 1 = 2" $ do
"(\\n f x. f (n f x)) (\\f x. f x)" `shouldEvalTo` "\\f x. f (f x)" it "add 3 2 = 5" $
"(\\m n f x. m f (n f x)) (\\f x. f (f (f x))) (\\f x. f (f x))"
describe "add" $ do `shouldEvalTo` "\\f x. f (f (f (f (f x))))"
-- add(m, n) = m + n
-- -- Here, we use `\f x. n f x` instead of `n`. This is because
-- It is defined by applying successor m times on n: -- I haven't implemented eta conversion
-- add = \m n f x. m f (n f x) it "add 0 n = n" $
it "add 0 2 = 2" $ do "(\\m n f x. m f (n f x)) (\\f x. x) n"
"(\\m n f x. m f (n f x)) (\\f x. x) (\\f x. f (f x))" `shouldEvalTo` "\\f x. n f x"
`shouldEvalTo` "\\f x. f (f x)"
describe "multiply" $ do
it "add 3 2 = 5" $ do -- multiply(m, n) = m * n
"(\\m n f x. m f (n f x)) (\\f x. f (f (f x))) (\\f x. f (f x))" --
`shouldEvalTo` "\\f x. f (f (f (f (f x))))" -- multiply is defined by applying add m times
-- multiply = \m n f x. m (n f x) x)
-- Here, we use `\f x. n f x` instead of `n`. This is because --
-- I haven't implemented eta conversion -- Using eta conversion, we can omit the parameter x
it "add 0 n = n" $ do -- multiply = \m n f. m (n f)
"(\\m n f x. m f (n f x)) (\\f x. x) n" it "multiply 0 2 = 0" $
`shouldEvalTo` "\\f x. n f x" "(\\m n f. m (n f)) (\\f x. x) (\\f x. f (f x))"
`shouldEvalTo` "\\f x. x"
describe "multiply" $ do
-- multiply(m, n) = m * n it "multiply 2 3 = 6" $
-- "(\\m n f. m (n f)) (\\f x. f (f x)) (\\f x. f (f (f x)))"
-- multiply is defined by applying add m times `shouldEvalTo` "\\f x. f (f (f (f (f (f x)))))"
-- multiply = \m n f x. m (n f x) x)
-- it "multiply 0 n = 0" $
-- Using eta conversion, we can omit the parameter x "(\\m n f. m (n f)) (\\f x. x) n"
-- multiply = \m n f. m (n f) `shouldEvalTo` "\\f x. x"
it "multiply 0 2 = 0" $ do
"(\\m n f. m (n f)) (\\f x. x) (\\f x. f (f x))" it "multiply 1 n = n" $
`shouldEvalTo` "\\f x. x" "(\\m n f. m (n f)) (\\f x. f x) n"
`shouldEvalTo` "\\f x. n f x"
it "multiply 2 3 = 6" $ do
"(\\m n f. m (n f)) (\\f x. f (f x)) (\\f x. f (f (f x)))" describe "power" $ do
`shouldEvalTo` "\\f x. f (f (f (f (f (f x)))))" -- The function power raises m to the power of n.
-- power(m, n) = m^n
it "multiply 0 n = 0" $ do --
"(\\m n f. m (n f)) (\\f x. x) n" -- power is defined by applying multiply n times
`shouldEvalTo` "\\f x. x" -- power = \m n f x. (n m) f x
--
it "multiply 1 n = n" $ do -- Using eta conversion again, we can omit the parameter f
"(\\m n f. m (n f)) (\\f x. f x) n" -- power = \m n = n m
`shouldEvalTo` "\\f x. n f x"
-- NOTE: Here we use the first form to get more predictable
describe "power" $ do -- variable names. Otherwise, alpha conversion will choose a random
-- The function power raises m to the power of n. -- unique variable.
-- power(m, n) = m^n it "power 0 1 = 0" $
-- "(\\m n f x. (n m) f x) (\\f x. x) (\\f x. f x)"
-- power is defined by applying multiply n times `shouldEvalTo` "\\f x. x"
-- power = \m n f x. (n m) f x
-- it "power 2 3 = 8" $
-- Using eta conversion again, we can omit the parameter f "(\\m n f x. (n m) f x) (\\f x. f (f x)) (\\f x. f (f (f x)))"
-- power = \m n = n m `shouldEvalTo` "\\f x. f (f (f (f (f (f (f (f x)))))))"
-- NOTE: Here we use the first form to get more predictable it "power n 0 = 1" $
-- variable names. Otherwise, alpha conversion will choose a random "(\\m n f x. (n m) f x) n (\\f x. x)"
-- unique variable. `shouldEvalTo` "\\f x. f x"
it "power 0 1 = 0" $ do
"(\\m n f x. (n m) f x) (\\f x. x) (\\f x. f x)" it "power n 1 = n" $
`shouldEvalTo` "\\f x. x" "(\\m n f x. (n m) f x) n (\\f x. f x)"
`shouldEvalTo` "\\f x. n f x"
it "power 2 3 = 8" $ do
"(\\m n f x. (n m) f x) (\\f x. f (f x)) (\\f x. f (f (f x)))"
`shouldEvalTo` "\\f x. f (f (f (f (f (f (f (f x)))))))"
it "power n 0 = 1" $ do
"(\\m n f x. (n m) f x) n (\\f x. x)"
`shouldEvalTo` "\\f x. f x"
it "power n 1 = n" $ do
"(\\m n f x. (n m) f x) n (\\f x. f x)"
`shouldEvalTo` "\\f x. n f x"
...@@ -5,35 +5,34 @@ import Language.Lambda.HspecUtils ...@@ -5,35 +5,34 @@ import Language.Lambda.HspecUtils
import Test.Hspec import Test.Hspec
spec :: Spec spec :: Spec
spec = do spec = describe "Pair" $ do
describe "Pair" $ do -- Pair is the definition of tuples with two items. Pairs,
-- Pair is the definition of tuples with two items. Pairs, -- again are represented using Church Encodings:
-- again are represented using Church Encodings: --
-- pair = \x y f. f x y
describe "first" $ do
-- The function first returns the first item in a pair
-- first(x, y) = x
-- --
-- pair = \x y f. f x y -- first is defined by
describe "first" $ do -- first = \p. p (\t f. t)
-- The function first returns the first item in a pair it "first 0 1 = 0" $
-- first(x, y) = x "(\\p. p (\\t f. t)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"
-- `shouldEvalTo` "\\f x. x"
-- first is defined by
-- first = \p. p (\t f. t)
it "first 0 1 = 0" $ do
"(\\p. p (\\t f. t)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"
`shouldEvalTo` "\\f x. x"
it "first x y = x" $ do it "first x y = x" $
"(\\p. p (\\t f. t)) ((\\x y f. f x y) x y)" `shouldEvalTo` "x" "(\\p. p (\\t f. t)) ((\\x y f. f x y) x y)" `shouldEvalTo` "x"
describe "second" $ do describe "second" $ do
-- The function second returns the second item in a pair -- The function second returns the second item in a pair
-- second(x, y) = y -- second(x, y) = y
-- --
-- second is defined by -- second is defined by
-- second = \p. p (\t f. f) -- second = \p. p (\t f. f)
it "second 0 1 = 1" $ do it "second 0 1 = 1" $
"(\\p. p (\\t f. f)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))" "(\\p. p (\\t f. f)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"
`shouldEvalTo` "\\f x. f x" `shouldEvalTo` "\\f x. f x"
it "second x y = y" $ do it "second x y = y" $ do
"(\\p. p (\\t f. f)) ((\\x y f. f x y) x y)" `shouldEvalTo` "y" "(\\p. p (\\t f. f)) ((\\x y f. f x y) x y)" `shouldEvalTo` "y"
"(\\p. p (\\x y z. x)) ((\\x y z f. f x y z) x y z)" `shouldEvalTo` "x" "(\\p. p (\\x y z. x)) ((\\x y z f. f x y z) x y z)" `shouldEvalTo` "x"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment