diff --git a/src/expr.rs b/src/expr.rs
index a8a8a8d6c4b73e533e3739c4b1ba6df3a8fac16b..c1652e2e54cbab0d3d5c4599f31ee65d1c3efcaa 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1,8 +1,14 @@
 #[derive(Debug)]
 pub enum Expr {
-    Lambda(Box<Expr>),
     Abs(Box<Expr>),
     App(Box<Expr>, Box<Expr>),
     Var(usize),
     DefinitionName(String),
 }
+
+#[derive(Debug)]
+pub enum FlattenedExpr {
+    Abs(Box<FlattenedExpr>),
+    App(Box<FlattenedExpr>, Box<FlattenedExpr>),
+    Var(usize),
+}
diff --git a/src/flatten.rs b/src/flatten.rs
new file mode 100644
index 0000000000000000000000000000000000000000..53e54322216c7149814fc28a6ffbb56219da29f1
--- /dev/null
+++ b/src/flatten.rs
@@ -0,0 +1,57 @@
+use std::collections::{HashMap, HashSet};
+
+use crate::expr::{Expr, FlattenedExpr};
+
+pub struct Flattener {
+    funcs: HashMap<String, Expr>,
+}
+
+impl Flattener {
+    pub fn new(funcs: HashMap<String, Expr>) -> Self {
+        Self { funcs }
+    }
+
+    pub fn flatten(&mut self, main: &Expr) -> Option<FlattenedExpr> {
+        self.flatten_expr(&main, HashSet::new())
+    }
+
+    fn flatten_expr<'a>(
+        &self,
+        expr: &'a Expr,
+        mut names: HashSet<&'a str>,
+    ) -> Option<FlattenedExpr> {
+        let ret = match expr {
+            Expr::Abs(expr) => FlattenedExpr::Abs(Box::new(self.flatten_expr(expr, names)?)),
+            Expr::App(left, right) => FlattenedExpr::App(
+                Box::new(self.flatten_expr(left, names.clone())?),
+                Box::new(self.flatten_expr(right, names)?),
+            ),
+            Expr::Var(x) => FlattenedExpr::Var(*x),
+            Expr::DefinitionName(name) => {
+                if names.contains(name.as_str()) {
+                    self.print_error(&format!("Recursive definition for ${}", name));
+                    return None;
+                }
+
+                let expr = match self.funcs.get(name) {
+                    Some(x) => x,
+                    None => {
+                        self.print_error(&format!("Unknown definition ${}", name));
+
+                        return None;
+                    }
+                };
+
+                names.insert(name);
+
+                self.flatten_expr(expr, names)?
+            }
+        };
+
+        Some(ret)
+    }
+
+    fn print_error(&self, err: &str) {
+        eprintln!("Error: {err}");
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 4de6c3e3e9a7aae9a53abb07ed1e1c12b820030b..5c2028210b9c56d6f34ce09e50690eb930663218 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,9 @@
+use flatten::Flattener;
 use parser::Parser;
 use scanner::Scanner;
 
 mod expr;
+mod flatten;
 mod parser;
 mod scanner;
 mod token;
@@ -10,7 +12,6 @@ fn main() {
     let scanner = Scanner::new(
         "
 $false = λtf.f
-# mrow!
 $true = λtf.t
 
 λa.(a $true)
@@ -19,13 +20,11 @@ $true = λtf.t
 
     let tokens = scanner.scan_tokens().unwrap();
 
-    for t in &tokens {
-        println!("{} {:?}", t.line, t.token_type);
-    }
-
     let mut parser = Parser::new(tokens);
     let (funcs, main) = parser.parse().unwrap();
 
-    dbg!(funcs);
-    dbg!(main);
+    let mut flattener = Flattener::new(funcs);
+    let flat = flattener.flatten(&main);
+
+    dbg!(flat);
 }
diff --git a/src/parser.rs b/src/parser.rs
index 8dd05f8e37f9c35b0f98ea258223d98d3b6acc4d..076388a2c7ae9ce63e75bcea0755e1d5a7e66512 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -122,7 +122,7 @@ impl Parser {
 
         for _ in 0..abs_count {
             self.env.pop().unwrap();
-            expr = Expr::Lambda(Box::new(expr));
+            expr = Expr::Abs(Box::new(expr));
         }
 
         Some(expr)