diff --git a/core/src/command.rs b/core/src/command.rs
index 0054e094c53cece6d8cb150876c6ffc7dfb9c068..e387449e0b417fd97f68d61cf83cb242baa6a6e5 100644
--- a/core/src/command.rs
+++ b/core/src/command.rs
@@ -1,7 +1,7 @@
 use crate::Term;
 use std::fmt::{Display, Formatter};
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub enum Command {
     Define(String, Term),
     CheckType(Term, Term),
diff --git a/core/src/term.rs b/core/src/term.rs
index acda4ef14e5b5600a27b4557241e12d57093eac6..016a918dd260cb93edab9222b3c7f20c4db11240 100644
--- a/core/src/term.rs
+++ b/core/src/term.rs
@@ -1,5 +1,9 @@
 use std::fmt::{Display, Formatter};
 
+// TODO: Use derive_more to constraint types (#11)
+// struct Index(usize);
+// struct Level(usize);
+
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub enum Term {
     Prop,
@@ -13,35 +17,29 @@ pub enum Term {
 use Term::*;
 
 impl Term {
-    /// Returns the normal form of the term
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// // TODO: Use parser
-    /// ```
+    /// Apply one step of β-reduction, using leftmost outermost evaluation strategy.
     pub fn beta_reduction(self) -> Term {
         match self {
             App(box Abs(_, box t1), box t2) => t1.substitute(t2, 1),
-            App(box t1, box t2) => App(box t1.beta_reduction(), box t2.beta_reduction()),
+            App(box t1, box t2) => App(box t1.beta_reduction(), box t2),
             Abs(x, box t) => Abs(x, box t.beta_reduction()),
             _ => self,
         }
     }
 
-    fn shift(self, offset: usize) -> Term {
+    fn shift(self, offset: usize, depth: usize) -> Term {
         match self {
-            Var(x) => Var(x + offset),
-            App(box t1, box t2) => App(box t1.shift(offset), box t2.shift(offset)),
-            Abs(x, box t) => Abs(x.clone(), box t.shift(offset)),
-            Prod(x, box t) => Prod(x.clone(), box t.shift(offset)),
-            _ => self.clone(),
+            Var(i) if i > depth => Var(i + offset),
+            App(box t1, box t2) => App(box t1.shift(offset, depth), box t2.shift(offset, depth)),
+            Abs(t1, box t2) => Abs(t1, box t2.shift(offset, depth + 1)),
+            Prod(t1, box t2) => Prod(t1, box t2.shift(offset, depth + 1)),
+            _ => self,
         }
     }
 
     fn substitute(self, rhs: Term, depth: usize) -> Term {
         match self {
-            Var(i) if i == depth => rhs.shift(depth - 1),
+            Var(i) if i == depth => rhs.shift(depth - 1, 0),
             Var(i) if i > depth => Var(i - 1),
 
             App(l, r) => App(
@@ -70,7 +68,7 @@ impl Display for Term {
 
 #[cfg(test)]
 mod tests {
-    // TODO: Correctly types lambda terms.
+    // TODO: Correctly types lambda terms (#9)
 
     use super::Term::*;
 
@@ -93,7 +91,7 @@ mod tests {
 
     #[test]
     fn complex_subst() {
-        // [λa.λb.λc.a (λd.λe.e (d b)) (λ_.c) (λd.d)] (λa.λb.a b)
+        // (λa.λb.λc.(a (λd.λe.e (d b) (λ_.c)) (λd.d)) (λa.λb.a b)
         let term = App(
             box Abs(
                 box Prop,
@@ -102,9 +100,9 @@ mod tests {
                     box Abs(
                         box Prop,
                         box App(
-                            box Var(3),
                             box App(
                                 box App(
+                                    box Var(3),
                                     box Abs(
                                         box Prop,
                                         box Abs(
@@ -112,10 +110,10 @@ mod tests {
                                             box App(box Var(1), box App(box Var(2), box Var(4))),
                                         ),
                                     ),
-                                    box Abs(box Prop, box Var(2)),
                                 ),
-                                box Abs(box Prop, box Var(1)),
+                                box Abs(box Prop, box Var(2)),
                             ),
+                            box Abs(box Prop, box Var(1)),
                         ),
                     ),
                 ),
@@ -123,20 +121,32 @@ mod tests {
             box Abs(box Prop, box Abs(box Prop, box App(box Var(2), box Var(1)))),
         );
 
-        // λa.λb.((λc.(λd.λe.e (d a)) c) (λ_.b)) (λc.c)
-        // λa.λb.((λc.λd.(d (c a))) (λ_.b)) (λc.c)
-        // λa.λb.(λc.c ((λ_.b) a)) (λc.c)
-        // λa.λb.(λc.c) ((λ_.b) a)
-        // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(term.beta_reduction(), reduced);
-    }
+        // λa.λb.(((λc.λd.c d) (λc.λd.d (c a))) (λ_.b)) (λc.c)
+        let term_step_1 = Abs(
+            box Prop,
+            box Abs(
+                box Prop,
+                box App(
+                    box App(
+                        box App(
+                            box Abs(box Prop, box Abs(box Prop, box App(box Var(2), box Var(1)))),
+                            box Abs(
+                                box Prop,
+                                box Abs(
+                                    box Prop,
+                                    box App(box Var(1), box App(box Var(2), box Var(4))),
+                                ),
+                            ),
+                        ),
+                        box Abs(box Prop, box Var(2)),
+                    ),
+                    box Abs(box Prop, box Var(1)),
+                ),
+            ),
+        );
 
-    #[test]
-    fn complex_subst_step_5() {
         // λa.λb.((λc.(λd.λe.e (d a)) c) (λ_.b)) (λc.c)
-        let term = Abs(
+        let term_step_2 = Abs(
             box Prop,
             box Abs(
                 box Prop,
@@ -162,23 +172,8 @@ mod tests {
             ),
         );
 
-        // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(
-            term.beta_reduction()
-                .beta_reduction()
-                .beta_reduction()
-                .beta_reduction()
-                .beta_reduction(),
-            reduced
-        );
-    }
-
-    #[test]
-    fn complex_subst_step_4() {
-        // λa.λb.((λc.λd.(d (c a))) (λ_.b)) (λc.c)
-        let term = Abs(
+        // λa.λb.[(λc.λd.(d (c a))) (λ_.b)] (λc.c)
+        let term_step_3 = Abs(
             box Prop,
             box Abs(
                 box Prop,
@@ -198,22 +193,8 @@ mod tests {
             ),
         );
 
-        // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(
-            term.beta_reduction()
-                .beta_reduction()
-                .beta_reduction()
-                .beta_reduction(),
-            reduced
-        );
-    }
-
-    #[test]
-    fn complex_subst_step_3() {
         // λa.λb.(λc.c ((λ_.b) a)) (λc.c)
-        let term = Abs(
+        let term_step_4 = Abs(
             box Prop,
             box Abs(
                 box Prop,
@@ -230,19 +211,8 @@ mod tests {
             ),
         );
 
-        // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(
-            term.beta_reduction().beta_reduction().beta_reduction(),
-            reduced
-        );
-    }
-
-    #[test]
-    fn complex_subst_step_2() {
         // λa.λb.(λc.c) ((λ_.b) a)
-        let term = Abs(
+        let term_step_5 = Abs(
             box Prop,
             box Abs(
                 box Prop,
@@ -253,23 +223,22 @@ mod tests {
             ),
         );
 
-        // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(term.beta_reduction().beta_reduction(), reduced);
-    }
-
-    #[test]
-    fn complex_subst_step_1() {
         // λa.λb.(λc.b) a
-        let term = Abs(
+        let term_step_6 = Abs(
             box Prop,
             box Abs(box Prop, box App(box Abs(box Prop, box Var(2)), box Var(2))),
         );
 
         // λa.λb.b
-        let reduced = Abs(box Prop, box Abs(box Prop, box Var(1)));
-
-        assert_eq!(term.beta_reduction(), reduced);
+        let term_step_7 = Abs(box Prop, box Abs(box Prop, box Var(1)));
+
+        assert_eq!(term.beta_reduction(), term_step_1);
+        assert_eq!(term_step_1.beta_reduction(), term_step_2);
+        assert_eq!(term_step_2.beta_reduction(), term_step_3);
+        assert_eq!(term_step_3.beta_reduction(), term_step_4);
+        assert_eq!(term_step_4.beta_reduction(), term_step_5);
+        assert_eq!(term_step_5.beta_reduction(), term_step_6);
+        assert_eq!(term_step_6.beta_reduction(), term_step_7);
+        assert_eq!(term_step_7.clone().beta_reduction(), term_step_7);
     }
 }