diff --git a/README.md b/README.md
index fa7cd86..af33a05 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # lib-laddertypes
 
-Rust Implementation of Ladder-Types (parsing, unification, rewriting, etc) 
+Rust Implementation of Ladder-Types (parsing, unification, rewriting, etc)
 <hr/>
 
 ## Ladder Types
@@ -121,16 +121,15 @@ fn main() {
 
 - [x] (Un-)Parsing
 - [x] (De-)Currying
-- [x] Unification
-- [x] Ladder-Normal-Form
-- [x] Parameter-Normal-Form
-- [ ] (De)-Sugaring
-  - [ ] Seq
-  - [ ] Enum
-  - [ ] Struct
-  - [ ] References
-  - [ ] Function
+- [x] Normal-Form
+- [x] Pretty Debug
+- [ ] Sugared Parser
+- [ ] Universal Types, Function Types
+- [x] Constraint Solving (Unification, Subtype Satisfaction)
+- [x] Morphism Graph
+  - [x] Complex Morphisms
+  - [x] Find Shortest Path
+  - [x] Approximate Steiner Tree
 
 ## License
 [GPLv3](COPYING)
-
diff --git a/src/unification_sugared.rs b/src/constraint_system.rs
similarity index 52%
rename from src/unification_sugared.rs
rename to src/constraint_system.rs
index f116f0b..80fa533 100644
--- a/src/unification_sugared.rs
+++ b/src/constraint_system.rs
@@ -1,56 +1,50 @@
 use {
-    crate::{dict::*, sugar::SugaredTypeTerm, term::*, SugaredEnumVariant, SugaredStructMember}, std::collections::HashMap
+    crate::{dict::*, term::TypeTerm, desugared_term::*, EnumVariant, StructMember, Substitution}, std::collections::HashMap
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 #[derive(Clone, Eq, PartialEq, Debug)]
-pub struct SugaredUnificationError {
+pub struct ConstraintError {
     pub addr: Vec<usize>,
-    pub t1: SugaredTypeTerm,
-    pub t2: SugaredTypeTerm
+    pub t1: TypeTerm,
+    pub t2: TypeTerm
 }
 
-// todo : rename -> ConstraintPair
 #[derive(Clone)]
-pub struct SugaredUnificationPair {
-    addr: Vec<usize>,
-    lhs: SugaredTypeTerm,
-    rhs: SugaredTypeTerm,
+pub struct ConstraintPair {
+    pub addr: Vec<usize>,
+    pub lhs: TypeTerm,
+    pub rhs: TypeTerm,
 }
 
-impl SugaredUnificationPair {
-    pub fn new(lhs: SugaredTypeTerm, rhs: SugaredTypeTerm) -> Self {
-        SugaredUnificationPair {
+impl ConstraintPair {
+    pub fn new(lhs: TypeTerm, rhs: TypeTerm) -> Self {
+        ConstraintPair {
             lhs,rhs, addr:vec![]
         }
     }
 }
 
-// todo : Rename -> ConstraintSystem
-pub struct SugaredUnificationProblem {
-   // dict: &'a Dict,
+pub struct ConstraintSystem {
+    σ: HashMap<TypeID, TypeTerm>,
+    upper_bounds: HashMap< u64, TypeTerm >,
+    lower_bounds: HashMap< u64, TypeTerm >,
 
-    σ: HashMap<TypeID, SugaredTypeTerm>,
-    upper_bounds: HashMap< u64, SugaredTypeTerm >,
-    lower_bounds: HashMap< u64, SugaredTypeTerm >,
-
-    equal_pairs: Vec<SugaredUnificationPair>,
-    subtype_pairs: Vec<SugaredUnificationPair>,
-    trait_pairs: Vec<SugaredUnificationPair>,
-    parallel_pairs: Vec<SugaredUnificationPair>
+    equal_pairs: Vec<ConstraintPair>,
+    subtype_pairs: Vec<ConstraintPair>,
+    trait_pairs: Vec<ConstraintPair>,
+    parallel_pairs: Vec<ConstraintPair>
 }
 
-impl SugaredUnificationProblem {
+impl ConstraintSystem {
     pub fn new(
-       // dict: &'a mut Dict,
-        equal_pairs: Vec<SugaredUnificationPair>,
-        subtype_pairs: Vec<SugaredUnificationPair>,
-        trait_pairs: Vec<SugaredUnificationPair>,
-        parallel_pairs: Vec<SugaredUnificationPair>
+        equal_pairs: Vec<ConstraintPair>,
+        subtype_pairs: Vec<ConstraintPair>,
+        trait_pairs: Vec<ConstraintPair>,
+        parallel_pairs: Vec<ConstraintPair>
     ) -> Self {
-        SugaredUnificationProblem {
-          //  dict,
+        ConstraintSystem {
             σ: HashMap::new(),
 
             equal_pairs,
@@ -63,20 +57,20 @@ impl SugaredUnificationProblem {
         }
     }
 
-    pub fn new_eq(eqs: Vec<SugaredUnificationPair>) -> Self {
-        SugaredUnificationProblem::new(  eqs, Vec::new(), Vec::new(), Vec::new() )
+    pub fn new_eq(eqs: Vec<ConstraintPair>) -> Self {
+        ConstraintSystem::new(  eqs, Vec::new(), Vec::new(), Vec::new() )
     }
 
-    pub fn new_sub( subs: Vec<SugaredUnificationPair>) -> Self {
-        SugaredUnificationProblem::new( Vec::new(), subs, Vec::new(), Vec::new() )
+    pub fn new_sub( subs: Vec<ConstraintPair>) -> Self {
+        ConstraintSystem::new( Vec::new(), subs, Vec::new(), Vec::new() )
     }
 
-    pub fn new_trait(traits: Vec<SugaredUnificationPair>) -> Self {
-        SugaredUnificationProblem::new( Vec::new(), Vec::new(), traits, Vec::new() )
+    pub fn new_trait(traits: Vec<ConstraintPair>) -> Self {
+        ConstraintSystem::new( Vec::new(), Vec::new(), traits, Vec::new() )
     }
 
-    pub fn new_parallel( parallels: Vec<SugaredUnificationPair>) -> Self {
-        SugaredUnificationProblem::new(Vec::new(), Vec::new(), Vec::new(), parallels )
+    pub fn new_parallel( parallels: Vec<ConstraintPair>) -> Self {
+        ConstraintSystem::new(Vec::new(), Vec::new(), Vec::new(), parallels )
     }
 
 
@@ -87,45 +81,45 @@ impl SugaredUnificationProblem {
             let mut tt = tt.clone();
             tt.apply_subst(&self.σ);
             //eprintln!("update σ : {:?} --> {:?}", v, tt);
-            new_σ.insert(v.clone(), tt);
+            new_σ.insert(v.clone(), tt.normalize());
         }
         self.σ = new_σ;
     }
 
 
-    pub fn eval_equation(&mut self, unification_pair: SugaredUnificationPair) -> Result<(), SugaredUnificationError> {
+    pub fn eval_equation(&mut self, unification_pair: ConstraintPair) -> Result<(), ConstraintError> {
         match (&unification_pair.lhs, &unification_pair.rhs) {
-            (SugaredTypeTerm::TypeID(TypeID::Var(varid)), t) |
-            (t, SugaredTypeTerm::TypeID(TypeID::Var(varid))) => {
+            (TypeTerm::TypeID(TypeID::Var(varid)), t) |
+            (t, TypeTerm::TypeID(TypeID::Var(varid))) => {
                 if ! t.contains_var( *varid ) {
                     self.σ.insert(TypeID::Var(*varid), t.clone());
                     self.reapply_subst();
                     Ok(())
-                } else if t == &SugaredTypeTerm::TypeID(TypeID::Var(*varid)) {
+                } else if t == &TypeTerm::TypeID(TypeID::Var(*varid)) {
                     Ok(())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(*varid)), t2: t.clone() })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(*varid)), t2: t.clone() })
                 }
             }
 
-            (SugaredTypeTerm::TypeID(a1), SugaredTypeTerm::TypeID(a2)) => {
-                if a1 == a2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
+            (TypeTerm::TypeID(a1), TypeTerm::TypeID(a2)) => {
+                if a1 == a2 { Ok(()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
             }
-            (SugaredTypeTerm::Num(n1), SugaredTypeTerm::Num(n2)) => {
-                if n1 == n2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
+            (TypeTerm::Num(n1), TypeTerm::Num(n2)) => {
+                if n1 == n2 { Ok(()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
             }
-            (SugaredTypeTerm::Char(c1), SugaredTypeTerm::Char(c2)) => {
-                if c1 == c2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
+            (TypeTerm::Char(c1), TypeTerm::Char(c2)) => {
+                if c1 == c2 { Ok(()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
             }
 
-            (SugaredTypeTerm::Ladder(a1), SugaredTypeTerm::Ladder(a2)) |
-            (SugaredTypeTerm::Spec(a1), SugaredTypeTerm::Spec(a2)) => {
+            (TypeTerm::Ladder(a1), TypeTerm::Ladder(a2)) |
+            (TypeTerm::Spec(a1), TypeTerm::Spec(a2)) => {
                 if a1.len() == a2.len() {
                     for (i, (x, y)) in a1.iter().cloned().zip(a2.iter().cloned()).enumerate().rev() {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
                         self.equal_pairs.push(
-                            SugaredUnificationPair {
+                            ConstraintPair {
                                 lhs: x,
                                 rhs: y,
                                 addr: new_addr
@@ -133,21 +127,21 @@ impl SugaredUnificationProblem {
                     }
                     Ok(())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
 
-            (SugaredTypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items },
-                SugaredTypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items })
+            (TypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items },
+                TypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items })
             => {
                 let mut new_addr = unification_pair.addr.clone();
                 new_addr.push(0);
 
                 if let Some(rhs_seq_repr) = rhs_seq_repr.as_ref() {
                     if let Some(lhs_seq_repr) = lhs_seq_repr.as_ref() {
-                        let _seq_repr_ψ = self.eval_equation(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_seq_repr.clone(), rhs: *rhs_seq_repr.clone() })?;
+                        let _seq_repr_ψ = self.eval_equation(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_seq_repr.clone(), rhs: *rhs_seq_repr.clone() })?;
                     } else {
-                        return Err(SugaredUnificationError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
@@ -157,80 +151,79 @@ impl SugaredUnificationProblem {
                     {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
-                        self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
+                        self.equal_pairs.push( ConstraintPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
                     }
                     Ok(())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
-            (SugaredTypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members },
-                SugaredTypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members })
+            (TypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members },
+                TypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members })
             => {
                 let new_addr = unification_pair.addr.clone();
                 if let Some(rhs_struct_repr) = rhs_struct_repr.as_ref() {
                     if let Some(lhs_struct_repr) = lhs_struct_repr.as_ref() {
-                        let _struct_repr_ψ = self.eval_subtype(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_struct_repr.clone(), rhs: *rhs_struct_repr.clone() })?;
+                        let _struct_repr_ψ = self.eval_subtype(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_struct_repr.clone(), rhs: *rhs_struct_repr.clone() })?;
                     } else {
-                        return Err(SugaredUnificationError{ addr: new_addr.clone(), t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr.clone(), t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
                 if lhs_members.len() == rhs_members.len() {
                     for (i,
-                            (SugaredStructMember{ symbol: lhs_symbol, ty: lhs_ty},
-                                SugaredStructMember{ symbol: rhs_symbol, ty: rhs_ty })
+                            (StructMember{ symbol: lhs_symbol, ty: lhs_ty},
+                                StructMember{ symbol: rhs_symbol, ty: rhs_ty })
                         ) in
                             lhs_members.into_iter().zip(rhs_members.into_iter()).enumerate()
                     {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
-                        self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
+                        self.equal_pairs.push( ConstraintPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
                     }
                     Ok(())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
-            (SugaredTypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants },
-                SugaredTypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants })
+            (TypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants },
+                TypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants })
             => {
                 let mut new_addr = unification_pair.addr.clone();
                 if let Some(rhs_enum_repr) = rhs_enum_repr.as_ref() {
                     if let Some(lhs_enum_repr) = lhs_enum_repr.as_ref() {
-                        let _enum_repr_ψ = self.eval_subtype(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_enum_repr.clone(), rhs: *rhs_enum_repr.clone() })?;
+                        let _enum_repr_ψ = self.eval_subtype(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_enum_repr.clone(), rhs: *rhs_enum_repr.clone() })?;
                     } else {
-                        return Err(SugaredUnificationError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
 
                 if lhs_variants.len() == rhs_variants.len() {
                     for (i,
-                            (SugaredEnumVariant{ symbol: lhs_symbol, ty: lhs_ty },
-                                SugaredEnumVariant{ symbol: rhs_symbol, ty: rhs_ty })
+                            (EnumVariant{ symbol: lhs_symbol, ty: lhs_ty },
+                                EnumVariant{ symbol: rhs_symbol, ty: rhs_ty })
                         ) in
                             lhs_variants.into_iter().zip(rhs_variants.into_iter()).enumerate()
                     {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
-                        self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
+                        self.equal_pairs.push( ConstraintPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } );
                     }
                     Ok(())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
 
-            _ => Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+            _ => Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
         }
     }
 
 
+    pub fn add_lower_subtype_bound(&mut self, v: u64, new_lower_bound: TypeTerm) -> Result<(),()> {
 
-    pub fn add_lower_subtype_bound(&mut self, v: u64, new_lower_bound: SugaredTypeTerm) -> Result<(),()> {
-
-        if new_lower_bound == SugaredTypeTerm::TypeID(TypeID::Var(v)) {
+        if new_lower_bound == TypeTerm::TypeID(TypeID::Var(v)) {
             return Ok(());
         }
 
@@ -240,42 +233,42 @@ impl SugaredUnificationProblem {
         }
 
         if let Some(lower_bound) = self.lower_bounds.get(&v).cloned() {
-//                        eprintln!("var already exists. check max. type");
+                        eprintln!("var already exists. check max. type");
             if let Ok(halo) = self.eval_subtype(
-                SugaredUnificationPair {
+                ConstraintPair {
                     lhs: lower_bound.clone(),
                     rhs: new_lower_bound.clone(),
                     addr: vec![]
                 }
             ) {
-//                            eprintln!("found more general lower bound");
-//                            eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone());
+                            eprintln!("found more general lower bound");
+                            eprintln!("set var {}'s lowerbound to {:?}", v, new_lower_bound.clone());
                 // generalize variable type to supertype
                 self.lower_bounds.insert(v, new_lower_bound);
                 Ok(())
             } else if let Ok(halo) = self.eval_subtype(
-                SugaredUnificationPair{
+                ConstraintPair{
                     lhs: new_lower_bound,
                     rhs: lower_bound,
                     addr: vec![]
                 }
             ) {
-//                            eprintln!("OK, is already larger type");
+                            eprintln!("OK, is already larger type");
                  Ok(())
             } else {
-//                            eprintln!("violated subtype restriction");
+                            eprintln!("violated subtype restriction");
                 Err(())
             }
         } else {
-//                        eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone());
+                        eprintln!("set var {}'s lowerbound to {:?}", v, new_lower_bound.clone());
             self.lower_bounds.insert(v, new_lower_bound);
             Ok(())
         }
     }
 
 
-    pub fn add_upper_subtype_bound(&mut self, v: u64, new_upper_bound: SugaredTypeTerm) -> Result<(),()> {
-        if new_upper_bound == SugaredTypeTerm::TypeID(TypeID::Var(v)) {
+    pub fn add_upper_subtype_bound(&mut self, v: u64, new_upper_bound: TypeTerm) -> Result<(),()> {
+        if new_upper_bound == TypeTerm::TypeID(TypeID::Var(v)) {
             return Ok(());
         }
 
@@ -286,52 +279,55 @@ impl SugaredUnificationProblem {
 
         if let Some(upper_bound) = self.upper_bounds.get(&v).cloned() {
             if let Ok(_halo) = self.eval_subtype(
-                SugaredUnificationPair {
+                ConstraintPair {
                     lhs: new_upper_bound.clone(),
                     rhs: upper_bound,
                     addr: vec![]
                 }
             ) {
+                eprintln!("found a lower upper bound: {} <= {:?}", v, new_upper_bound);
                 // found a lower upper bound
                 self.upper_bounds.insert(v, new_upper_bound);
                 Ok(())
             } else {
+                eprintln!("new upper bound violates subtype restriction");
                 Err(())
             }
         } else {
+            eprintln!("set upper bound: {} <= {:?}", v, new_upper_bound);
             self.upper_bounds.insert(v, new_upper_bound);
             Ok(())
         }
     }
 
-    pub fn eval_subtype(&mut self, unification_pair: SugaredUnificationPair) -> Result<
+    pub fn eval_subtype(&mut self, unification_pair: ConstraintPair) -> Result<
         // ok: halo type
-        SugaredTypeTerm,
+        TypeTerm,
         // error
-        SugaredUnificationError
+        ConstraintError
     > {
-       // eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs);
+        eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs);
         match (unification_pair.lhs.clone().strip(), unification_pair.rhs.clone().strip()) {
 
             /*
              Variables
             */
 
-            (t, SugaredTypeTerm::TypeID(TypeID::Var(v))) => {
+            (t, TypeTerm::TypeID(TypeID::Var(v))) => {
                 //eprintln!("t <= variable");
                 if self.add_lower_subtype_bound(v, t.clone()).is_ok() {
-                    Ok(SugaredTypeTerm::unit())
+                    Ok(TypeTerm::unit())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(v)), t2: t })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(v)), t2: t })
                 }
             }
 
-            (SugaredTypeTerm::TypeID(TypeID::Var(v)), t) => {
+            (TypeTerm::TypeID(TypeID::Var(v)), t) => {
                 //eprintln!("variable <= t");
                 if self.add_upper_subtype_bound(v, t.clone()).is_ok() {
-                    Ok(SugaredTypeTerm::unit())
+                    Ok(TypeTerm::unit())
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(v)), t2: t })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(v)), t2: t })
                 }
             }
 
@@ -339,22 +335,22 @@ impl SugaredUnificationProblem {
             /*
              Atoms
             */
-            (SugaredTypeTerm::TypeID(a1), SugaredTypeTerm::TypeID(a2)) => {
-                if a1 == a2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs}) }
+            (TypeTerm::TypeID(a1), TypeTerm::TypeID(a2)) => {
+                if a1 == a2 { Ok(TypeTerm::unit()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs}) }
             }
-            (SugaredTypeTerm::Num(n1), SugaredTypeTerm::Num(n2)) => {
-                if n1 == n2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
+            (TypeTerm::Num(n1), TypeTerm::Num(n2)) => {
+                if n1 == n2 { Ok(TypeTerm::unit()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
             }
-            (SugaredTypeTerm::Char(c1), SugaredTypeTerm::Char(c2)) => {
-                if c1 == c2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
+            (TypeTerm::Char(c1), TypeTerm::Char(c2)) => {
+                if c1 == c2 { Ok(TypeTerm::unit()) } else { Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
             }
 
             /*
              Complex Types
             */
 
-            (SugaredTypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items },
-                SugaredTypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items })
+            (TypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items },
+                TypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items })
             => {
                 let mut new_addr = unification_pair.addr.clone();
                 new_addr.push(0);
@@ -363,97 +359,97 @@ impl SugaredUnificationProblem {
                     //eprintln!("subtype unify: rhs has seq-repr: {:?}", rhs_seq_repr);
                     if let Some(lhs_seq_repr) = lhs_seq_repr.as_ref() {
                         //eprintln!("check if it maches lhs seq-repr: {:?}", lhs_seq_repr);
-                        let _seq_repr_ψ = self.eval_subtype(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_seq_repr.clone(), rhs: *rhs_seq_repr.clone() })?;
+                        let _seq_repr_ψ = self.eval_subtype(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_seq_repr.clone(), rhs: *rhs_seq_repr.clone() })?;
                         //eprintln!("..yes!");
                     } else {
                         //eprintln!("...but lhs has none.");
-                        return Err(SugaredUnificationError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
                 let mut new_addr = unification_pair.addr.clone();
                 new_addr.push(1);
                 if lhs_items.len() == rhs_items.len() && lhs_items.len() > 0 {
-                    match self.eval_subtype( SugaredUnificationPair { addr: new_addr.clone(), lhs: lhs_items[0].clone(), rhs: rhs_items[0].clone() } ) {
-                        Ok(ψ) => Ok(SugaredTypeTerm::Seq {
+                    match self.eval_subtype( ConstraintPair { addr: new_addr.clone(), lhs: lhs_items[0].clone(), rhs: rhs_items[0].clone() } ) {
+                        Ok(ψ) => Ok(TypeTerm::Seq {
                                 seq_repr: None, // <<- todo
                                 items: vec![ψ]
                             }.strip()),
-                        Err(e) => Err(SugaredUnificationError{
+                        Err(e) => Err(ConstraintError{
                                 addr: new_addr,
                                 t1: e.t1,
                                 t2: e.t2,
                             })
                     }
                 } else {
-                    Err(SugaredUnificationError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
-            (SugaredTypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members },
-                SugaredTypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members })
+            (TypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members },
+                TypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members })
             => {
                 let new_addr = unification_pair.addr.clone();
                 if let Some(rhs_struct_repr) = rhs_struct_repr.as_ref() {
                     if let Some(lhs_struct_repr) = lhs_struct_repr.as_ref() {
-                        let _struct_repr_ψ = self.eval_subtype(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_struct_repr.clone(), rhs: *rhs_struct_repr.clone() })?;
+                        let _struct_repr_ψ = self.eval_subtype(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_struct_repr.clone(), rhs: *rhs_struct_repr.clone() })?;
                     } else {
-                        return Err(SugaredUnificationError{ addr: new_addr.clone(), t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr.clone(), t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
                 if lhs_members.len() == rhs_members.len() {
                     let mut halo_members = Vec::new();
                     for (i,
-                            (SugaredStructMember{ symbol: lhs_symbol, ty: lhs_ty},
-                                SugaredStructMember{ symbol: rhs_symbol, ty: rhs_ty })
+                            (StructMember{ symbol: lhs_symbol, ty: lhs_ty},
+                                StructMember{ symbol: rhs_symbol, ty: rhs_ty })
                         ) in
                             lhs_members.into_iter().zip(rhs_members.into_iter()).enumerate()
                     {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
 
-                        let ψ = self.eval_subtype( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?;
-                        halo_members.push(SugaredStructMember { symbol: lhs_symbol, ty: ψ });
+                        let ψ = self.eval_subtype( ConstraintPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?;
+                        halo_members.push(StructMember { symbol: lhs_symbol, ty: ψ });
                     }
-                    Ok(SugaredTypeTerm::Struct {
+                    Ok(TypeTerm::Struct {
                         struct_repr: None,
                         members: halo_members
                     })
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
-            (SugaredTypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants },
-                SugaredTypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants })
+            (TypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants },
+                TypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants })
             => {
                 let mut new_addr = unification_pair.addr.clone();
                 if let Some(rhs_enum_repr) = rhs_enum_repr.as_ref() {
                     if let Some(lhs_enum_repr) = lhs_enum_repr.as_ref() {
-                        let _enum_repr_ψ = self.eval_subtype(SugaredUnificationPair { addr: new_addr.clone(), lhs: *lhs_enum_repr.clone(), rhs: *rhs_enum_repr.clone() })?;
+                        let _enum_repr_ψ = self.eval_subtype(ConstraintPair { addr: new_addr.clone(), lhs: *lhs_enum_repr.clone(), rhs: *rhs_enum_repr.clone() })?;
                     } else {
-                        return Err(SugaredUnificationError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
+                        return Err(ConstraintError{ addr: new_addr, t1: unification_pair.lhs, t2: unification_pair.rhs });
                     }
                 }
 
                 if lhs_variants.len() == rhs_variants.len() {
                     let mut halo_variants = Vec::new();
                     for (i,
-                            (SugaredEnumVariant{ symbol: lhs_symbol, ty: lhs_ty },
-                                SugaredEnumVariant{ symbol: rhs_symbol, ty: rhs_ty })
+                            (EnumVariant{ symbol: lhs_symbol, ty: lhs_ty },
+                                EnumVariant{ symbol: rhs_symbol, ty: rhs_ty })
                         ) in
                             lhs_variants.into_iter().zip(rhs_variants.into_iter()).enumerate()
                     {
                         let mut new_addr = unification_pair.addr.clone();
                         new_addr.push(i);
-                        let ψ = self.eval_subtype( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?;
-                        halo_variants.push(SugaredEnumVariant { symbol: lhs_symbol, ty: ψ });
+                        let ψ = self.eval_subtype( ConstraintPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?;
+                        halo_variants.push(EnumVariant { symbol: lhs_symbol, ty: ψ });
                     }
-                    Ok(SugaredTypeTerm::Enum {
+                    Ok(TypeTerm::Enum {
                         enum_repr: None,
                         variants: halo_variants
                     })
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
 
@@ -463,7 +459,7 @@ impl SugaredUnificationProblem {
              Ladders
             */
 
-            (SugaredTypeTerm::Ladder(a1), SugaredTypeTerm::Ladder(a2)) => {
+            (TypeTerm::Ladder(a1), TypeTerm::Ladder(a2)) => {
 
                 let mut l1_iter = a1.into_iter().enumerate().rev();
                 let mut l2_iter = a2.into_iter().rev();
@@ -479,16 +475,13 @@ impl SugaredUnificationProblem {
                         //eprintln!("addr = {:?}", addr);
 
                         match (lhs.clone(), rhs.clone()) {
-                            (t, SugaredTypeTerm::TypeID(TypeID::Var(v))) => {
+                            (t, TypeTerm::TypeID(TypeID::Var(v))) => {
 
                                 if self.add_upper_subtype_bound(v,t.clone()).is_ok() {
                                     let mut new_upper_bound_ladder = vec![ t ];
 
                                     if let Some(next_rhs) = l2_iter.next() {
 
-                                        // TODO
-                                        todo!();
-
                                     } else {
                                         // ladder of rhs is empty
                                         // take everything
@@ -499,17 +492,17 @@ impl SugaredUnificationProblem {
                                     }
 
                                     new_upper_bound_ladder.reverse();
-                                    if self.add_upper_subtype_bound(v, SugaredTypeTerm::Ladder(new_upper_bound_ladder)).is_ok() {
+                                    if self.add_upper_subtype_bound(v, TypeTerm::Ladder(new_upper_bound_ladder)).is_ok() {
                                         // ok
                                     } else {
-                                        return Err(SugaredUnificationError {
+                                        return Err(ConstraintError {
                                             addr,
                                             t1: lhs,
                                             t2: rhs
                                         });
                                     }
                                 } else {
-                                    return Err(SugaredUnificationError {
+                                    return Err(ConstraintError {
                                         addr,
                                         t1: lhs,
                                         t2: rhs
@@ -518,7 +511,7 @@ impl SugaredUnificationProblem {
                             }
                             (lhs, rhs) => {
                                 if let Ok(ψ) = self.eval_subtype(
-                                    SugaredUnificationPair {
+                                    ConstraintPair {
                                         lhs: lhs.clone(),
                                         rhs: rhs.clone(),
                                         addr:addr.clone(),
@@ -528,7 +521,7 @@ impl SugaredUnificationProblem {
                                     //eprintln!("rungs are subtypes. continue");
                                     halo_ladder.push(ψ);
                                 } else {
-                                    return Err(SugaredUnificationError {
+                                    return Err(ConstraintError {
                                         addr,
                                         t1: lhs,
                                         t2: rhs
@@ -538,13 +531,14 @@ impl SugaredUnificationProblem {
                         }
                     } else {
                         // not a subtype,
-                        return Err(SugaredUnificationError {
+                        return Err(ConstraintError {
                             addr: vec![],
                             t1: unification_pair.lhs,
                             t2: unification_pair.rhs
                         });
                     }
                 }
+
                 //eprintln!("left ladder fully consumed");
 
                 for (i,t) in l1_iter {
@@ -552,19 +546,94 @@ impl SugaredUnificationProblem {
                     halo_ladder.push(t);
                 }
                 halo_ladder.reverse();
-                Ok(SugaredTypeTerm::Ladder(halo_ladder).strip())//.param_normalize())
+                Ok(TypeTerm::Ladder(halo_ladder).strip())//.param_normalize())
             },
 
-            (t, SugaredTypeTerm::Ladder(a1)) => {
-                Err(SugaredUnificationError{ addr: unification_pair.addr, t1: t, t2: SugaredTypeTerm::Ladder(a1) })
+            (TypeTerm::Seq { seq_repr, items }, TypeTerm::Spec(mut args)) => {
+                let mut new_addr = unification_pair.addr.clone();
+                let mut n_halos_required = 0;
+                if args.len() > 1 {
+                    if let Some(seq_repr) = seq_repr {
+                        let rhs = args.remove(0);
+                        let reprψinterface = rhs.get_interface_type();
+                        let mut reprψ = self.eval_subtype(ConstraintPair{
+                            addr: new_addr.clone(),
+                            lhs: seq_repr.as_ref().clone(),
+                            rhs
+                        })?;
+
+                        let mut itemsψ = Vec::new();
+                        for (i,(item, arg)) in items.iter().zip(args.iter()).enumerate() {
+                            let mut new_addr = new_addr.clone();
+                            new_addr.push(i);
+                            let ψ = self.eval_subtype(ConstraintPair {
+                                addr: new_addr,
+                                lhs: item.clone(),
+                                rhs: arg.clone()
+                            })?;
+
+                            if ψ.is_empty() {
+                                itemsψ.push(item.get_interface_type());
+                            } else {
+                                if n_halos_required == 0 {
+                                    // first argument that requires halo,
+                                    // add highest-common-rung to sequence repr
+                                    reprψ = TypeTerm::Ladder(vec![
+                                        reprψ,
+                                        reprψinterface.clone()
+                                    ]).normalize();
+                                } else {
+                                    /* todo
+                                    if let Some(mut t) = itemsψ.last_mut() {
+                                        t = TypeTerm::Ladder(vec![
+                                            t.clone(),
+                                            args[i]
+                                        ]).normalize();
+                                    } else {
+                                        t =
+                                    }
+                                    */
+                                }
+
+                                n_halos_required += 1;
+
+                                itemsψ.push(ψ);
+                            }
+                        }
+                        eprintln!("itemsψ = {:?}", itemsψ);
+                        Ok(
+                            TypeTerm::Seq {
+                                seq_repr: if reprψ.is_empty() { None }
+                                          else { Some(Box::new(reprψ)) },
+                                items: itemsψ
+                            }
+                        )
+                    } else {
+                        Err(ConstraintError {
+                            addr: new_addr,
+                            t1: unification_pair.lhs,
+                            t2: unification_pair.rhs
+                        })
+                    }
+                } else {
+                    Err(ConstraintError {
+                        addr: unification_pair.addr,
+                        t1: unification_pair.lhs,
+                        t2: unification_pair.rhs
+                    })
+                }
             }
 
-            (SugaredTypeTerm::Ladder(mut a1), t) => {
+            (t, TypeTerm::Ladder(a1)) => {
+                Err(ConstraintError{ addr: unification_pair.addr, t1: t, t2: TypeTerm::Ladder(a1) })
+            }
+
+            (TypeTerm::Ladder(mut a1), t) => {
                 if a1.len() > 0 {
                     let mut new_addr = unification_pair.addr.clone();
-                    new_addr.push( a1.len() -1 );
+                    new_addr.push( a1.len() - 1 );
                     if let Ok(halo) = self.eval_subtype(
-                        SugaredUnificationPair {
+                        ConstraintPair {
                             lhs: a1.pop().unwrap(),
                             rhs: t.clone(),
                             addr: new_addr
@@ -574,15 +643,15 @@ impl SugaredUnificationProblem {
                         if a1.len() == 1 {
                             Ok(a1.pop().unwrap())
                         } else {
-                            Ok(SugaredTypeTerm::Ladder(a1))
+                            Ok(TypeTerm::Ladder(a1).normalize())
                         }
                     } else {
-                        Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::Ladder(a1), t2: t })
+                        Err(ConstraintError{ addr: unification_pair.addr, t1: TypeTerm::Ladder(a1), t2: t })
                     }
-                } else if t == SugaredTypeTerm::unit() {
-                    Ok(SugaredTypeTerm::unit())
+                } else if t == TypeTerm::unit() {
+                    Ok(TypeTerm::unit())
                 } else {
-                    Err(SugaredUnificationError { addr: unification_pair.addr, t1: SugaredTypeTerm::unit(), t2: t })
+                    Err(ConstraintError { addr: unification_pair.addr, t1: TypeTerm::unit(), t2: t })
                 }
             }
 
@@ -591,7 +660,7 @@ impl SugaredUnificationProblem {
              Application
             */
 
-            (SugaredTypeTerm::Spec(a1), SugaredTypeTerm::Spec(a2)) => {
+            (TypeTerm::Spec(a1), TypeTerm::Spec(a2)) => {
                 if a1.len() == a2.len() {
                     let mut halo_args = Vec::new();
                     let mut n_halos_required = 0;
@@ -608,14 +677,14 @@ impl SugaredUnificationProblem {
 //                        eprintln!("APP<> eval {:?} \n ?<=? {:?} ", x, y);
 
                         match self.eval_subtype(
-                            SugaredUnificationPair {
+                            ConstraintPair {
                                 lhs: x.clone(),
                                 rhs: y.clone(),
                                 addr: new_addr,
                             }
                         ) {
                             Ok(halo) => {
-                                if halo == SugaredTypeTerm::unit() {
+                                if halo == TypeTerm::unit() {
                                     let mut y = y.clone();
                                     y.apply_subst(&self.σ);
                                     y = y.strip();
@@ -627,12 +696,12 @@ impl SugaredUnificationProblem {
                                     //println!("add halo {}", halo.pretty(self.dict, 0));
                                     if n_halos_required > 0 {
                                         let x = &mut halo_args[n_halos_required-1];
-                                        if let SugaredTypeTerm::Ladder(arg_rungs) = x {
+                                        if let TypeTerm::Ladder(arg_rungs) = x {
                                             let mut a = a2[n_halos_required-1].clone();
                                             a.apply_subst(&self.σ);
                                             arg_rungs.push(a.get_interface_type());
                                         } else {
-                                            *x = SugaredTypeTerm::Ladder(vec![
+                                            *x = TypeTerm::Ladder(vec![
                                                 x.clone(),
                                                 a2[n_halos_required-1].get_interface_type()
                                             ]);
@@ -651,20 +720,20 @@ impl SugaredUnificationProblem {
 
                     if n_halos_required > 0 {
                         //eprintln!("halo args : {:?}", halo_args);
-                        Ok(SugaredTypeTerm::Spec(halo_args))
+                        Ok(TypeTerm::Spec(halo_args))
                     } else {
-                        Ok(SugaredTypeTerm::unit())
+                        Ok(TypeTerm::unit())
                     }
                 } else {
-                    Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+                    Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
                 }
             }
 
-            _ => Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
+            _ => Err(ConstraintError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
         }
     }
 
-    pub fn solve(mut self) -> Result<(Vec<SugaredTypeTerm>, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> {
+    pub fn solve(mut self) -> Result<(Vec<TypeTerm>, HashMap<TypeID, TypeTerm>), ConstraintError> {
         // solve equations
         while let Some( mut equal_pair ) = self.equal_pairs.pop() {
             equal_pair.lhs.apply_subst(&self.σ);
@@ -674,7 +743,7 @@ impl SugaredUnificationProblem {
         }
 
         // solve subtypes
-        //eprintln!("------ SOLVE SUBTYPES ---- ");
+        eprintln!("------ SOLVE SUBTYPES ---- ");
         for mut subtype_pair in self.subtype_pairs.clone().into_iter() {
             subtype_pair.lhs.apply_subst(&self.σ);
             subtype_pair.rhs.apply_subst(&self.σ);
@@ -694,17 +763,11 @@ impl SugaredUnificationProblem {
 
         self.reapply_subst();
 
-        //eprintln!("------ MAKE HALOS -----");
+        eprintln!("------ MAKE HALOS -----");
         let mut halo_types = Vec::new();
         for mut subtype_pair in self.subtype_pairs.clone().into_iter() {
-            subtype_pair.lhs = subtype_pair.lhs.apply_subst(&self.σ).clone().strip();
-            subtype_pair.rhs = subtype_pair.rhs.apply_subst(&self.σ).clone().strip();
-
-            subtype_pair.lhs.apply_subst(&self.σ);
-            subtype_pair.rhs.apply_subst(&self.σ);
-
-           // eprintln!("find halo.\n lhs={}", subtype_pair.lhs.pretty(self.dict,0));
-           // eprintln!("rhs={}", subtype_pair.rhs.pretty(self.dict,0));
+            subtype_pair.lhs = subtype_pair.lhs.apply_subst(&self.σ).clone();
+            subtype_pair.rhs = subtype_pair.rhs.apply_subst(&self.σ).clone();
 
             let halo = self.eval_subtype( subtype_pair.clone() )?.strip();
             halo_types.push(halo);
@@ -720,27 +783,27 @@ impl SugaredUnificationProblem {
 }
 
 pub fn unify(
-    t1: &SugaredTypeTerm,
-    t2: &SugaredTypeTerm
-) -> Result<HashMap<TypeID, SugaredTypeTerm>, SugaredUnificationError> {
-    let unification = SugaredUnificationProblem::new_eq(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
+    t1: &TypeTerm,
+    t2: &TypeTerm
+) -> Result<HashMap<TypeID, TypeTerm>, ConstraintError> {
+    let unification = ConstraintSystem::new_eq(vec![ ConstraintPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
     Ok(unification.solve()?.1)
 }
 
 pub fn subtype_unify(
-    t1: &SugaredTypeTerm,
-    t2: &SugaredTypeTerm
-) -> Result<(SugaredTypeTerm, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> {
-    let unification = SugaredUnificationProblem::new_sub(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
-    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(SugaredTypeTerm::unit()), σ) )
+    t1: &TypeTerm,
+    t2: &TypeTerm
+) -> Result<(TypeTerm, HashMap<TypeID, TypeTerm>), ConstraintError> {
+    let unification = ConstraintSystem::new_sub(vec![ ConstraintPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
+    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) )
 }
 
 pub fn parallel_unify(
-    t1: &SugaredTypeTerm,
-    t2: &SugaredTypeTerm
-) -> Result<(SugaredTypeTerm, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> {
-    let unification = SugaredUnificationProblem::new_parallel(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
-    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(SugaredTypeTerm::unit()), σ) )
+    t1: &TypeTerm,
+    t2: &TypeTerm
+) -> Result<(TypeTerm, HashMap<TypeID, TypeTerm>), ConstraintError> {
+    let unification = ConstraintSystem::new_parallel(vec![ ConstraintPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]);
+    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) )
 }
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/curry.rs b/src/curry.rs
index 1c6deab..add8999 100644
--- a/src/curry.rs
+++ b/src/curry.rs
@@ -1,12 +1,12 @@
-use crate::term::*;
+use crate::desugared_term::*;
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
-impl TypeTerm {
+impl DesugaredTypeTerm {
     /// transform term to have at max 2 entries in Application list
-    pub fn curry(self) -> TypeTerm {
+    pub fn curry(self) -> DesugaredTypeTerm {
         match self {
-            TypeTerm::App(args) => {
+            DesugaredTypeTerm::App(args) => {
                 if args.len() >= 2 {
                     let mut old_args = args.into_iter();
                     let mut new_args = vec![
@@ -16,19 +16,19 @@ impl TypeTerm {
 
                     for x in old_args {
                         new_args = vec![
-                            TypeTerm::App(new_args),
+                            DesugaredTypeTerm::App(new_args),
                             x
                         ];
                     }
 
-                    TypeTerm::App(new_args)
+                    DesugaredTypeTerm::App(new_args)
                 } else {
-                    TypeTerm::App(args)
+                    DesugaredTypeTerm::App(args)
                 }
             }
 
-            TypeTerm::Ladder(rungs) => {
-                TypeTerm::Ladder(rungs.into_iter().map(|r| r.curry()).collect())
+            DesugaredTypeTerm::Ladder(rungs) => {
+                DesugaredTypeTerm::Ladder(rungs.into_iter().map(|r| r.curry()).collect())
             }
 
             _ => self
@@ -38,11 +38,11 @@ impl TypeTerm {
     /// summarize all curried applications into one vec
     pub fn decurry(self) -> Self {
         match self {
-            TypeTerm::App(mut args) => {
+            DesugaredTypeTerm::App(mut args) => {
                 if args.len() > 0 {
                     let a0 = args.remove(0).decurry();
                     match a0 {
-                        TypeTerm::App(sub_args) => {
+                        DesugaredTypeTerm::App(sub_args) => {
                             for (i,x) in sub_args.into_iter().enumerate() {
                                 args.insert(i, x);
                             }
@@ -50,10 +50,10 @@ impl TypeTerm {
                         other => { args.insert(0, other); }
                     }
                 }
-                TypeTerm::App(args)
+                DesugaredTypeTerm::App(args)
             }
-            TypeTerm::Ladder(args) => {
-                TypeTerm::Ladder(args.into_iter().map(|a| a.decurry()).collect())
+            DesugaredTypeTerm::Ladder(args) => {
+                DesugaredTypeTerm::Ladder(args.into_iter().map(|a| a.decurry()).collect())
             }
             _ => self
         }
diff --git a/src/desugared_term.rs b/src/desugared_term.rs
new file mode 100644
index 0000000..fa975a3
--- /dev/null
+++ b/src/desugared_term.rs
@@ -0,0 +1,155 @@
+use crate::TypeID;
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum DesugaredTypeTerm {
+
+    /* Atomic Terms */
+
+    // Base types from dictionary
+    TypeID(TypeID),
+
+    // Literals
+    Num(i64),
+    Char(char),
+
+    /* Complex Terms */
+
+    // Type Parameters
+    // avoid currying to save space & indirection
+    App(Vec< DesugaredTypeTerm >),
+
+    // Type Ladders
+    Ladder(Vec< DesugaredTypeTerm >),
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
+
+impl DesugaredTypeTerm {
+    pub fn unit() -> Self {
+        DesugaredTypeTerm::Ladder(vec![])
+    }
+
+    pub fn new(id: TypeID) -> Self {
+        DesugaredTypeTerm::TypeID(id)
+    }
+
+    pub fn arg(&mut self, t: impl Into<DesugaredTypeTerm>) -> &mut Self {
+        match self {
+            DesugaredTypeTerm::App(args) => {
+                args.push(t.into());
+            }
+
+            _ => {
+                *self = DesugaredTypeTerm::App(vec![
+                    self.clone(),
+                    t.into()
+                ])
+            }
+        }
+        self
+    }
+
+    pub fn repr_as(&mut self, t: impl Into<DesugaredTypeTerm>) -> &mut Self {
+        match self {
+            DesugaredTypeTerm::Ladder(rungs) => {
+                rungs.push(t.into());
+            }
+
+            _ => {
+                *self = DesugaredTypeTerm::Ladder(vec![
+                    self.clone(),
+                    t.into()
+                ])
+            }
+        }
+
+        self
+    }
+
+    pub fn num_arg(&mut self, v: i64) -> &mut Self {
+        self.arg(DesugaredTypeTerm::Num(v))
+    }
+
+    pub fn char_arg(&mut self, c: char) -> &mut Self {
+        self.arg(DesugaredTypeTerm::Char(c))
+    }
+
+    pub fn contains_var(&self, var_id: u64) -> bool {
+        match self {
+            DesugaredTypeTerm::TypeID(TypeID::Var(v)) => (&var_id == v),
+            DesugaredTypeTerm::App(args) |
+            DesugaredTypeTerm::Ladder(args) => {
+                for a in args.iter() {
+                    if a.contains_var(var_id) {
+                        return true;
+                    }
+                }
+                false
+            }
+            _ => false
+        }
+    }
+
+
+    /* strip away empty ladders
+     * & unwrap singletons
+     */
+    pub fn strip(self) -> Self {
+        match self {
+            DesugaredTypeTerm::Ladder(rungs) => {
+                let mut rungs :Vec<_> = rungs.into_iter()
+                    .filter_map(|mut r| {
+                        r = r.strip();
+                        if r != DesugaredTypeTerm::unit() {
+                            Some(match r {
+                                DesugaredTypeTerm::Ladder(r) => r,
+                                a => vec![ a ]
+                            })
+                        }
+                        else { None }
+                    })
+                .flatten()
+                .collect();
+
+                if rungs.len() == 1 {
+                    rungs.pop().unwrap()
+                } else {
+                    DesugaredTypeTerm::Ladder(rungs)
+                }
+            },
+            DesugaredTypeTerm::App(args) => {
+                let mut args :Vec<_> = args.into_iter().map(|arg| arg.strip()).collect();
+                if args.len() == 0 {
+                    DesugaredTypeTerm::unit()
+                } else if args.len() == 1 {
+                    args.pop().unwrap()
+                } else {
+                    DesugaredTypeTerm::App(args)
+                }
+            }
+            atom => atom
+        }
+    }
+
+
+
+    pub fn get_interface_type(&self) -> DesugaredTypeTerm {
+        match self {
+            DesugaredTypeTerm::Ladder(rungs) => {
+                if let Some(top) = rungs.first() {
+                    top.get_interface_type()
+                } else {
+                    DesugaredTypeTerm::unit()
+                }
+            }
+            DesugaredTypeTerm::App(args) => {
+                DesugaredTypeTerm::App(args.iter().map(|a| a.get_interface_type()).collect())
+            }
+            atom => atom.clone()
+        }
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/lib.rs b/src/lib.rs
index 882082c..35950b7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,33 +4,18 @@ pub mod bimap;
 pub mod dict;
 
 pub mod lexer;
-pub mod parser;
+pub mod parser; // todo sugared variant
+pub mod curry; // todo: sugared variant
+//pub mod subtype; // deprecated
 pub mod unparser;
-pub mod curry;
-
-pub mod lnf; // deprecated
-pub mod subtype; // deprecated
-
-pub mod pnf;
-pub mod pnf_sugared;
-
+pub mod desugared_term; // deprecated
 pub mod term;
-pub mod sugar;
-
+pub mod pnf;
 pub mod substitution;
-pub mod substitution_sugared;
-
-pub mod unification;
-pub mod unification_sugared;
-
+pub mod constraint_system;
 pub mod morphism;
-pub mod morphism_sugared;
-
 pub mod morphism_base;
-pub mod morphism_base_sugared;
-
 pub mod morphism_path;
-pub mod morphism_path_sugared;
 
 pub mod steiner_tree;
 
@@ -42,27 +27,29 @@ mod pretty;
 
 pub use {
     dict::*,
-    term::*,
+    desugared_term::*,
     substitution::*,
-    sugar::*,
-    unification::*,
-    morphism::*
+    term::*,
+    constraint_system::*,
+    morphism::*,
+    morphism_base::*,
+    morphism_path::*,
 };
 
-
+/*
 pub fn common_halo(
-    a: &TypeTerm,
-    b: &TypeTerm
-) -> Option< TypeTerm > {
+    a: &DesugaredTypeTerm,
+    b: &DesugaredTypeTerm
+) -> Option< DesugaredTypeTerm > {
     match (a,b) {
-        (TypeTerm::Ladder(rs1), TypeTerm::Ladder(rs2)) => {
+        (DesugaredTypeTerm::Ladder(rs1), DesugaredTypeTerm::Ladder(rs2)) => {
             let mut halo_rungs = Vec::new();
 
             for (r1, r2) in rs1.iter().zip(rs2.iter()) {
                 if let Some(h) = common_halo(r1, r2) {
                     halo_rungs.push(h);
                 } else {
-                    return Some(TypeTerm::Ladder(halo_rungs).normalize());
+                    return Some(DesugaredTypeTerm::Ladder(halo_rungs).normalize());
                 }
             }
 
@@ -70,36 +57,36 @@ pub fn common_halo(
 
                 None
             } else {
-                Some(TypeTerm::Ladder(halo_rungs).normalize())
+                Some(DesugaredTypeTerm::Ladder(halo_rungs).normalize())
             }
         }
 
-        (TypeTerm::App(a1), TypeTerm::App(a2)) => {
+        (DesugaredTypeTerm::App(a1), DesugaredTypeTerm::App(a2)) => {
             let mut halo_args = Vec::new();
 
             for (r1, r2) in a1.iter().zip(a2.iter()) {
                 if let Some(h) = common_halo(r1, r2) {
                     halo_args.push(h);
                 } else {
-                    return Some(TypeTerm::Ladder(halo_args).normalize());
+                    return Some(DesugaredTypeTerm::Ladder(halo_args).normalize());
                 }
             }
 
             if halo_args.len() == 0 {
                 None
             } else {
-                Some(TypeTerm::App(halo_args).normalize())
+                Some(DesugaredTypeTerm::App(halo_args).normalize())
             }
         }
 
-        (TypeTerm::Ladder(rsl), r) => {
+        (DesugaredTypeTerm::Ladder(rsl), r) => {
             if rsl.first().unwrap() == r {
                 Some(r.clone())
             } else {
                 None
             }
         }
-        (l, TypeTerm::Ladder(rsr)) => {
+        (l, DesugaredTypeTerm::Ladder(rsr)) => {
             if rsr.first().unwrap() == l {
                 Some(l.clone())
             } else {
@@ -116,3 +103,4 @@ pub fn common_halo(
         }
     }
 }
+*/
diff --git a/src/lnf.rs b/src/lnf.rs
deleted file mode 100644
index b284df5..0000000
--- a/src/lnf.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use crate::term::TypeTerm;
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-impl TypeTerm {
-    /// does the type contain ladders (false) or is it 'flat' (true) ?
-    ///
-    /// Example:
-    /// ```<Seq <Digit 10>>``` is flat, but
-    /// ```<Digit 10>~Char``` is not
-    pub fn is_flat(&self) -> bool {
-        match self {
-            TypeTerm::TypeID(_) => true,
-            TypeTerm::Num(_) => true,
-            TypeTerm::Char(_) => true,
-            TypeTerm::App(args) => args.iter().fold(true, |s,x| s && x.is_flat()),
-            TypeTerm::Ladder(_) => false
-        }
-    }
-
-    /// transmute type into Ladder-Normal-Form (LNF)
-    ///
-    /// Example:
-    /// ```ignore
-    /// <Seq <Digit 10>~Char>
-    /// ⇒ <Seq <Digit 10>>~<Seq Char>
-    /// ```
-    pub fn normalize(self) -> Self {
-        let mut new_ladder = Vec::<TypeTerm>::new();
-
-        match self {
-            TypeTerm::Ladder(args) => {
-                for x in args.into_iter() {
-                    match x.normalize() {
-                        TypeTerm::Ladder(gs) => {
-                            for g in gs {
-                                new_ladder.push(g);
-                            }
-                        }
-                        g => {
-                            new_ladder.push(g);
-                        }
-                    }
-                }
-            }
-
-            TypeTerm::App(args) => {
-                let args_iter = args.into_iter();
-
-                new_ladder.push( TypeTerm::App(vec![]) );
-
-                for arg in args_iter {
-                    match arg.normalize() {
-                        TypeTerm::Ladder(rungs) => {
-                            // duplicate last element for each rung
-                            let l = new_ladder.len();
-                            for _ in 1..rungs.len() {
-                                new_ladder.push( new_ladder.last().unwrap().clone() );
-                            }
-
-                            for (i,r) in new_ladder.iter_mut().enumerate() {
-                                match r {
-                                    TypeTerm::App(al) => {
-                                        if i < l {
-                                            al.push(rungs[0].clone());
-                                        } else {
-                                            al.push(rungs[i-l+1].clone());
-                                        }
-                                    }
-                                    _ => unreachable!()
-                                }
-                            }
-                        }
-                        mut other => {
-                            other = other.normalize();
-                            for rung in new_ladder.iter_mut() {
-                                match rung {
-                                    TypeTerm::App(al) => {
-                                        al.push(other.clone());
-                                    }
-                                    _ => unreachable!()
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            atom => {
-                new_ladder.push(atom);
-            }
-        }
-
-        match new_ladder.len() {
-            0 => TypeTerm::unit(),
-            1 => new_ladder.into_iter().next().unwrap(),
-            _ => TypeTerm::Ladder( new_ladder )
-        }
-    }
-    
-    /// transmute type into a `Vec` containing
-    /// all rungs of the type in LNF
-    ///
-    /// Example:
-    /// ```<Seq <Digit 10>~Char>``` gives
-    /// ```ignore
-    /// vec![ <Seq <Digit 10>>,  <Seq Char> ]
-    /// ```
-    pub fn get_lnf_vec(self) -> Vec<TypeTerm> {
-        match self.normalize() {
-            TypeTerm::Ladder( v ) => {
-                v
-            },
-            flat => vec![ flat ]
-        }
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/morphism.rs b/src/morphism.rs
index dc99b38..eae1bb6 100644
--- a/src/morphism.rs
+++ b/src/morphism.rs
@@ -1,68 +1,381 @@
 use {
     crate::{
-        pnf::splice_ladders,
-        substitution_sugared::SugaredSubstitution,
-        subtype_unify,
-        sugar::{SugaredStructMember, SugaredTypeTerm},
-        unification::UnificationProblem,
-        unification_sugared::SugaredUnificationProblem,
-        unparser::*,
-        TypeDict, TypeID, TypeTerm
+        substitution::Substitution, term::{StructMember, TypeTerm},
+        constraint_system::ConstraintSystem, unparser::*, EnumVariant, TypeDict, TypeID
     },
     std::{collections::HashMap, u64}
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct MorphismType {
     pub src_type: TypeTerm,
-    pub dst_type: TypeTerm,
+    pub dst_type: TypeTerm
 }
 
 impl MorphismType {
-    pub fn normalize(self) -> Self {
+    pub fn strip_halo(&self) -> MorphismType {
+        match (&self.src_type.clone().strip(), &self.dst_type.clone().strip()) {
+            (TypeTerm::Ladder(rungs_lhs), TypeTerm::Ladder(rungs_rhs)) => {
+
+                let mut lhs_iter = rungs_lhs.iter();
+                let mut rhs_iter = rungs_rhs.iter();
+                let mut last = MorphismType { src_type: TypeTerm::unit(), dst_type: TypeTerm::unit() };
+
+                while let (Some(lhs_top), Some(rhs_top)) = (lhs_iter.next(), rhs_iter.next()) {
+                    last = MorphismType{
+                        src_type: lhs_top.clone(),
+                        dst_type: rhs_top.clone()
+                    };
+
+                    if lhs_top != rhs_top {
+                        let x = MorphismType{ src_type: lhs_top.clone(), dst_type: rhs_top.clone() }.strip_halo();
+
+                        let mut rl : Vec<_> = lhs_iter.cloned().collect();
+                        rl.insert(0, x.src_type);
+                        let mut rr : Vec<_> = rhs_iter.cloned().collect();
+                        rr.insert(0, x.dst_type);
+
+                        return MorphismType {
+                            src_type: TypeTerm::Ladder(rl),
+                            dst_type: TypeTerm::Ladder(rr)
+                        };
+                    }
+                }
+
+                last
+            }
+
+            (TypeTerm::Spec(args_lhs), TypeTerm::Spec(args_rhs)) => {
+
+                let (rl, rr) = args_lhs.iter().zip(args_rhs.iter()).map(
+                    |(al,ar)| MorphismType{ src_type: al.clone(), dst_type: ar.clone() }.strip_halo()
+                )
+                .fold((vec![], vec![]), |(mut rl, mut rr), x| {
+                    rl.push(x.src_type);
+                    rr.push(x.dst_type);
+                    (rl,rr)
+                });
+
+                MorphismType {
+                    src_type: TypeTerm::Spec(rl),
+                    dst_type: TypeTerm::Spec(rr)
+                }
+            }
+
+            (TypeTerm::Seq { seq_repr:seq_repr_lhs, items:items_lhs },
+                TypeTerm::Seq { seq_repr: seq_repr_rhs, items:items_rhs })
+            => {
+                let (rl, rr) = items_lhs.iter().zip(items_rhs.iter()).map(
+                    |(al,ar)| MorphismType{ src_type: al.clone(), dst_type: ar.clone() }.strip_halo()
+                )
+                .fold((vec![], vec![]), |(mut rl, mut rr), x| {
+                    rl.push(x.src_type);
+                    rr.push(x.dst_type);
+                    (rl,rr)
+                });
+                MorphismType  {
+                    src_type: TypeTerm::Seq{ seq_repr: seq_repr_lhs.clone(), items: rl },
+                    dst_type: TypeTerm::Seq { seq_repr: seq_repr_rhs.clone(), items: rr }
+                }
+            }
+
+            (TypeTerm::Struct { struct_repr:struct_repr_lhs, members:members_lhs },
+                TypeTerm::Struct { struct_repr: struct_repr_rhs, members:members_rhs })
+            => {
+                let mut rl = Vec::new();
+                let mut rr = Vec::new();
+
+                for ar in members_rhs.iter() {
+                    let mut found = false;
+                    for al in members_lhs.iter() {
+                        if al.symbol == ar.symbol {
+                            let x = MorphismType{ src_type: al.ty.clone(), dst_type: ar.ty.clone() }.strip_halo();
+                            rl.push( StructMember{
+                                symbol: al.symbol.clone(),
+                                ty: x.src_type
+                            });
+                            rr.push( StructMember{
+                                symbol: ar.symbol.clone(),
+                                ty: x.dst_type
+                            });
+                            found = true;
+                            break;
+                        }
+                    }
+
+                    if !found {
+                        return MorphismType {
+                            src_type: TypeTerm::Struct { struct_repr: struct_repr_lhs.clone(), members:members_lhs.clone() },
+                            dst_type: TypeTerm::Struct { struct_repr: struct_repr_rhs.clone(), members:members_rhs.clone() }
+                        };
+                    }
+                }
+
+                MorphismType  {
+                    src_type: TypeTerm::Struct{ struct_repr: struct_repr_lhs.clone(), members: rl },
+                    dst_type: TypeTerm::Struct{ struct_repr: struct_repr_rhs.clone(), members: rr }
+                }
+            }
+
+            (TypeTerm::Enum { enum_repr:enum_repr_lhs, variants:variants_lhs },
+                TypeTerm::Enum { enum_repr: enum_repr_rhs, variants:variants_rhs })
+            => {
+                let mut rl = Vec::new();
+                let mut rr = Vec::new();
+
+                for ar in variants_rhs.iter() {
+                    let mut found = false;
+                    for al in variants_lhs.iter() {
+                        if al.symbol == ar.symbol {
+                            let x = MorphismType{ src_type: al.ty.clone(), dst_type: ar.ty.clone() }.strip_halo();
+                            rl.push( EnumVariant{
+                                symbol: al.symbol.clone(),
+                                ty: x.src_type
+                            });
+                            rr.push( EnumVariant{
+                                symbol: ar.symbol.clone(),
+                                ty: x.dst_type
+                            });
+                            found = true;
+                            break;
+                        }
+                    }
+
+                    if !found {
+                        return MorphismType {
+                            src_type: TypeTerm::Enum { enum_repr: enum_repr_lhs.clone(), variants:variants_lhs.clone() },
+                            dst_type: TypeTerm::Enum { enum_repr: enum_repr_rhs.clone(), variants:variants_rhs.clone() }
+                        };
+                    }
+                }
+
+                MorphismType  {
+                    src_type: TypeTerm::Enum{ enum_repr: enum_repr_lhs.clone(), variants: rl },
+                    dst_type: TypeTerm::Enum { enum_repr: enum_repr_rhs.clone(), variants: rr }
+                }
+            }
+
+            (x,y) => MorphismType { src_type: x.clone(), dst_type: y.clone() }
+        }
+    }
+
+    pub fn apply_subst(&self, σ: &impl Substitution) -> MorphismType {
         MorphismType {
-            src_type: self.src_type.strip().param_normalize(),
-            dst_type: self.dst_type.strip().param_normalize(),
+            src_type: self.src_type.clone().apply_subst(σ).clone(),
+            dst_type: self.dst_type.clone().apply_subst(σ).clone()
+        }
+    }
+
+
+    pub fn normalize(&self) -> MorphismType {
+        MorphismType {
+            src_type: self.src_type.clone().normalize(),
+            dst_type: self.dst_type.clone().normalize(),
         }
     }
 }
 
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
 pub trait Morphism : Sized {
     fn get_type(&self) -> MorphismType;
-    fn map_morphism(&self, seq_type: TypeTerm) -> Option< Self >;
-
     fn weight(&self) -> u64 {
         1
     }
 }
 
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct MorphismInstance<M: Morphism + Clone> {
-    pub halo: TypeTerm,
-    pub m: M,
-    pub σ: HashMap<TypeID, TypeTerm>
-}
-
-impl<M: Morphism + Clone> MorphismInstance<M> {
-    pub fn get_type(&self) -> MorphismType {
-        MorphismType {
-            src_type: TypeTerm::Ladder(vec![
-                self.halo.clone(),
-                self.m.get_type().src_type.clone()
-            ]).apply_subst(&self.σ)
-            .clone(),
-
-            dst_type: TypeTerm::Ladder(vec![
-                self.halo.clone(),
-                self.m.get_type().dst_type.clone()
-            ]).apply_subst(&self.σ)
-            .clone(),
-        }.normalize()
+#[derive(Clone, PartialEq, Debug)]
+pub enum MorphismInstance<M: Morphism + Clone> {
+    Primitive{
+        ψ: TypeTerm,
+        σ: HashMap<TypeID, TypeTerm>,
+        morph: M,
+    },
+    Chain{
+        path: Vec<MorphismInstance<M>>
+    },
+    MapSeq{
+        ψ: TypeTerm,
+        seq_repr: Option<Box<TypeTerm>>,
+        item_morph: Box<MorphismInstance<M>>,
+    },
+    MapStruct{
+        ψ: TypeTerm,
+        src_struct_repr: Option<Box<TypeTerm>>,
+        dst_struct_repr: Option<Box<TypeTerm>>,
+        member_morph: Vec< (String, MorphismInstance<M>) >
+    },
+    MapEnum{
+        ψ: TypeTerm,
+        enum_repr: Option<Box<TypeTerm>>,
+        variant_morph: Vec< (String, MorphismInstance<M>) >
     }
 }
+
+
+impl<M: Morphism + Clone> MorphismInstance<M> {
+    pub fn get_haloless_type(&self) -> MorphismType {
+        self.get_type().strip_halo()
+    }
+
+    pub fn get_type(&self) -> MorphismType {
+        match self {
+            MorphismInstance::Primitive { ψ, σ, morph } => {
+                MorphismType {
+                    src_type:
+                        TypeTerm::Ladder(vec![
+                            ψ.clone(),
+                            morph.get_type().src_type
+                                .apply_subst(σ).clone()
+                        ]).strip(),
+
+                    dst_type: TypeTerm::Ladder(vec![
+                            ψ.clone(),
+                            morph.get_type().dst_type
+                                .apply_subst(σ).clone()
+                        ]).strip(),
+                }
+            }
+            MorphismInstance::Chain { path } => {
+                if path.len() > 0 {
+                    let s = self.get_subst();
+                    MorphismType {
+                        src_type: path.first().unwrap().get_type().src_type.clone(),
+                        dst_type: path.last().unwrap().get_type().dst_type.clone()
+                    }.apply_subst(&s)
+                } else {
+                    MorphismType {
+                        src_type: TypeTerm::TypeID(TypeID::Fun(45454)),
+                        dst_type: TypeTerm::TypeID(TypeID::Fun(45454))
+                    }
+                }
+            }
+            MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
+                MorphismType {
+                    src_type: TypeTerm::Ladder(vec![
+                        ψ.clone(),
+                        TypeTerm::Seq{ seq_repr: seq_repr.clone(),
+                            items: vec![ item_morph.get_type().src_type ]}
+                    ]),
+                    dst_type: TypeTerm::Ladder(vec![
+                        ψ.clone(),
+                        TypeTerm::Seq{ seq_repr: seq_repr.clone(),
+                            items: vec![ item_morph.get_type().dst_type ]}
+                    ])
+                }
+            }
+            MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
+                MorphismType {
+                    src_type: TypeTerm::Ladder(vec![ ψ.clone(),
+                            TypeTerm::Struct{
+                                struct_repr: src_struct_repr.clone(),
+                                members:
+                                    member_morph.iter().map(|(symbol, morph)| {
+                                       StructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
+                                    }).collect()
+                            }
+                        ]),
+                    dst_type: TypeTerm::Ladder(vec![ ψ.clone(),
+                            TypeTerm::Struct{
+                                struct_repr: dst_struct_repr.clone(),
+                                members: member_morph.iter().map(|(symbol, morph)| {
+                                    StructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
+                                }).collect()
+                            }
+                        ])
+                }
+            }
+            MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
+                MorphismType {
+                    src_type: TypeTerm::Ladder(vec![ ψ.clone(),
+                            TypeTerm::Struct{
+                                struct_repr: enum_repr.clone(),
+                                members:
+                                    variant_morph.iter().map(|(symbol, morph)| {
+                                       StructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
+                                    }).collect()
+                            }
+                        ]),
+                    dst_type: TypeTerm::Ladder(vec![ ψ.clone(),
+                            TypeTerm::Struct{
+                                struct_repr: enum_repr.clone(),
+                                members: variant_morph.iter().map(|(symbol, morph)| {
+                                    StructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
+                                }).collect()
+                            }
+                        ])
+                }
+            }
+        }.normalize()
+    }
+
+    pub fn get_subst(&self) -> std::collections::HashMap< TypeID, TypeTerm > {
+        match self {
+            MorphismInstance::Primitive { ψ, σ, morph } => σ.clone(),
+            MorphismInstance::Chain { path } => {
+                path.iter().fold(
+                    std::collections::HashMap::new(),
+                    |mut σ, m| {
+                        σ = σ.append(&m.get_subst());
+                        σ
+                    }
+                )
+            },
+            MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
+                item_morph.get_subst()
+            },
+            MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
+                let mut σ = HashMap::new();
+                for (symbol, m) in member_morph.iter() {
+                    σ = σ.append(&mut m.get_subst());
+                }
+                σ
+            },
+            MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
+                todo!();
+                HashMap::new()
+            },
+        }
+    }
+
+    pub fn apply_subst(&mut self, γ: &std::collections::HashMap< TypeID, TypeTerm >) {
+        let ty = self.get_type();
+        match self {
+            MorphismInstance::Primitive { ψ, σ, morph } => {
+                ψ.apply_subst(γ);
+                for (n,t) in σ.iter_mut() {
+                    t.apply_subst(γ);
+                }
+                for (n,t) in γ.iter() {
+                    if let TypeID::Var(varid) = n {
+                        if morph.get_type().src_type.apply_subst(σ).contains_var(*varid)
+                        || morph.get_type().dst_type.apply_subst(σ).contains_var(*varid) {
+                            σ.insert(n.clone(), t.clone());
+                        }
+                    }
+                }
+            },
+            MorphismInstance::Chain { path } => {
+                for n in path.iter_mut() {
+                    n.apply_subst(γ);
+                }
+            }
+            MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
+                ψ.apply_subst(γ);
+                item_morph.apply_subst(γ);
+            }
+            MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
+                for (_,ty) in member_morph {
+                    ty.apply_subst(γ);
+                }
+            },
+            MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
+                for (_,ty) in variant_morph {
+                    ty.apply_subst(γ);
+                }
+            }
+        }
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/morphism_base.rs b/src/morphism_base.rs
index f922046..fdd3760 100644
--- a/src/morphism_base.rs
+++ b/src/morphism_base.rs
@@ -1,24 +1,24 @@
 use {
     crate::{
-        morphism::{Morphism, MorphismInstance, MorphismType}, morphism_path_sugared::SugaredShortestPathProblem, morphism_sugared::{MorphismInstance2, SugaredMorphismType}, subtype_unify, sugar::SugaredTypeTerm, unification::UnificationProblem, TypeDict, TypeID, TypeTerm
-    }
+        morphism_path::{MorphismPath, ShortestPathProblem},
+        morphism::{MorphismInstance, Morphism, MorphismType},
+        TypeTerm, StructMember, TypeDict, TypeID
+    }, std::io::{Read, Write}
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 #[derive(Clone)]
 pub struct MorphismBase<M: Morphism + Clone> {
-    morphisms: Vec< M >,
-    seq_types: Vec< TypeTerm >
+    morphisms: Vec< M >
 }
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 impl<M: Morphism + Clone> MorphismBase<M> {
-    pub fn new(seq_types: Vec<TypeTerm>) -> Self {
+    pub fn new() -> Self {
         MorphismBase {
-            morphisms: Vec::new(),
-            seq_types
+            morphisms: Vec::new()
         }
     }
 
@@ -26,156 +26,165 @@ impl<M: Morphism + Clone> MorphismBase<M> {
         self.morphisms.push( m );
     }
 
-    pub fn enum_direct_morphisms(&self, src_type: &TypeTerm)
-    -> Vec< MorphismInstance<M> >
-    {
-        let mut dst_types = Vec::new();
-        for m in self.morphisms.iter() {
-            if let Ok((halo, σ)) = crate::unification::subtype_unify(
-                &src_type.clone().param_normalize(),
-                &m.get_type().src_type.param_normalize(),
-            ) {
-                dst_types.push(MorphismInstance{ halo, m: m.clone(), σ });
+    pub fn get_morphism_instance(&self, ty: &MorphismType) -> Option<MorphismInstance<M>> {
+        if let Some(path) = ShortestPathProblem::new(self, ty.clone()).solve() {
+            if path.len() == 1 {
+                Some(path[0].clone())
+            } else {
+                Some(MorphismInstance::Chain { path })
             }
+        } else {
+            None
         }
-        dst_types
     }
 
-    pub fn enum_map_morphisms(&self, src_type: &TypeTerm)
-    -> Vec< MorphismInstance<M> > {
-        let src_type = src_type.clone().param_normalize();
-        let mut dst_types = Vec::new();
+    pub fn complex_morphism_decomposition(&self, src_type: &TypeTerm, dst_type: &TypeTerm) -> Option< MorphismInstance<M> > {
+        let (src_ψ, src_floor) = src_type.get_floor_type();
+        let (dst_ψ, dst_floor) = dst_type.get_floor_type();
 
-        // Check if we have a List type, and if so, see what the Item type is
-        // TODO: function for generating fresh variables
-        let item_variable = TypeID::Var(800);
+        if !dst_ψ.is_empty() {
+            if !crate::constraint_system::subtype_unify(&src_ψ, &dst_ψ).is_ok() {
+                return None;
+            }
+        }
 
-        for seq_type in self.seq_types.iter() {
-            if let Ok((halo, σ)) = crate::unification::subtype_unify(
-                &src_type,
-                &TypeTerm::App(vec![
-                    seq_type.clone(),
-                    TypeTerm::TypeID(item_variable)
-                ])
-            ) {
-                let src_item_type = σ.get(&item_variable).expect("var not in unificator").clone();
-                for item_morph_inst in self.enum_morphisms( &src_item_type ) {
+        match (src_floor, dst_floor) {
+            (TypeTerm::Struct{ struct_repr: struct_repr_lhs, members: members_lhs},
+                TypeTerm::Struct { struct_repr: struct_repr_rhs, members: members_rhs })
+            => {
+                // todo: optimization: check if struct repr match
 
-                    let mut dst_halo_ladder = vec![ halo.clone() ];
-                    if item_morph_inst.halo != TypeTerm::unit() {
-                        dst_halo_ladder.push(
-                            TypeTerm::App(vec![
-                                seq_type.clone().get_lnf_vec().first().unwrap().clone(),
-                                item_morph_inst.halo.clone()
-                            ]));
-                    }
+                let mut member_morph = Vec::new();
+                let mut failed = false;
+                let mut necessary = false;
 
-                    if let Some( map_morph ) = item_morph_inst.m.map_morphism( seq_type.clone() ) {
-                        dst_types.push(
-                            MorphismInstance {
-                                halo: TypeTerm::Ladder(dst_halo_ladder).strip().param_normalize(),
-                                m: map_morph,
-                                σ: item_morph_inst.σ
+                for StructMember{ symbol: symbol_rhs, ty: ty_rhs } in members_rhs.iter() {
+                    let mut found_src_member = false;
+                    for StructMember{ symbol: symbol_lhs, ty: ty_lhs } in members_lhs.iter() {
+                        if symbol_rhs == symbol_lhs {
+                            found_src_member = true;
+
+                            if let Some(mm) = self.get_morphism_instance(&MorphismType { src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) {
+                                if ty_lhs != ty_rhs {
+                                    necessary = true;
+                                }
+                                member_morph.push((symbol_lhs.clone(), mm))
+                            } else {
+                                failed = true;
                             }
-                        );
-                    } else {
-                        eprintln!("could not get map morphism");
+                            break;
+                        }
+                    }
+
+                    // member of rhs not found in lhs
+                    if ! found_src_member {
+                        failed = true;
+                        break;
                     }
                 }
+
+                if ! failed && necessary {
+                    Some(MorphismInstance::MapStruct {
+                        ψ: src_ψ,
+                        src_struct_repr: struct_repr_lhs.clone(),
+                        dst_struct_repr: struct_repr_rhs.clone(),
+                        member_morph
+                    })
+                } else {
+                    None
+                }
+            }
+
+
+            (TypeTerm::Seq{ seq_repr: seq_repr_lhs, items: items_lhs },
+                TypeTerm::Seq{ seq_repr: _seq_rerpr_rhs, items: items_rhs })
+            => {
+                //let mut item_morphs = Vec::new();
+
+                for (ty_lhs, ty_rhs) in items_lhs.iter().zip(items_rhs.iter()) {
+                    if let Some(item_morph) = self.get_morphism_instance(&MorphismType{ src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) {
+                        return Some(MorphismInstance::MapSeq { ψ: src_ψ, seq_repr: seq_repr_lhs.clone(), item_morph: Box::new(item_morph) });
+                    }
+                    break;
+                }
+                None
+            }
+
+            _ => {
+                None
             }
         }
-
-        dst_types
     }
 
-    pub fn enum_morphisms(&self, src_type: &TypeTerm) -> Vec< MorphismInstance<M> > {
-        let mut dst_types = Vec::new();
-        dst_types.append(&mut self.enum_direct_morphisms(src_type));
-        dst_types.append(&mut self.enum_map_morphisms(src_type));
-        dst_types
-    }
+    pub fn enum_morphisms_from(&self, src_type: &TypeTerm) -> Vec< MorphismInstance<M> > {
+        let mut morphs = Vec::new();
 
-    pub fn find_direct_morphism(&self,
-        ty: &MorphismType,
-        dict: &mut impl TypeDict
-    ) -> Option< MorphismInstance<M> > {
-        //eprintln!("find direct morph");
+        //eprintln!("enum morphisms from {:?}", src_type);
         for m in self.morphisms.iter() {
-            let ty = ty.clone().normalize();
-            let morph_type = m.get_type().normalize();
-            /*
-            eprintln!("find direct morph:\n   {}  <=   {}",
-                            dict.unparse(&ty.src_type), dict.unparse(&morph_type.src_type),
-                        );
-*/
-            if let Ok((halo, σ)) = subtype_unify(&ty.src_type, &morph_type.src_type) {
-                //eprintln!("halo: {}", dict.unparse(&halo));
+            let m_src_type = m.get_type().src_type;
+            let m_dst_type = m.get_type().dst_type;
 
-                let dst_type = TypeTerm::Ladder(vec![
-                    halo.clone(),
-                    morph_type.dst_type.clone()
-                ]).normalize().param_normalize();
-/*
-                eprintln!("----------->   {}  <=   {}",
-                    dict.unparse(&dst_type), dict.unparse(&ty.dst_type)
-                );
-*/
-                if let Ok((halo2, σ2)) = subtype_unify(&dst_type, &ty.dst_type) {
-                   //eprintln!("match. halo2 = {}", dict.unparse(&halo2));
-                    return Some(MorphismInstance {
-                        m: m.clone(),
-                        halo,
-                        σ,
-                    });
-                }
+            /* 1. primitive morphisms */
+
+            // check if the given start type is compatible with the
+            // morphisms source type,
+            // i.e. check if `src_type` is a subtype of `m_src_type`
+            if let Ok((ψ, σ)) = crate::constraint_system::subtype_unify(src_type, &m_src_type) {
+                let morph_inst = MorphismInstance::Primitive { ψ, σ, morph: m.clone() };
+                //eprintln!("..found direct morph to {:?}", morph_inst.get_type().dst_type);
+                morphs.push(morph_inst);
             }
-        }
-        None
-    }
 
-    pub fn find_map_morphism(&self, ty: &MorphismType, dict: &mut impl TypeDict) -> Option< MorphismInstance<M> > {
-        for seq_type in self.seq_types.iter() {
-            if let Ok((halos, σ)) = UnificationProblem::new_sub(vec![
-                (ty.src_type.clone().param_normalize(),
-                    TypeTerm::App(vec![ seq_type.clone(), TypeTerm::TypeID(TypeID::Var(100)) ])),
-
-                (TypeTerm::App(vec![ seq_type.clone(), TypeTerm::TypeID(TypeID::Var(101)) ]),
-                    ty.dst_type.clone().param_normalize()),
-            ]).solve() {
-                // TODO: use real fresh variable names
-                let item_morph_type = MorphismType {
-                    src_type: σ.get(&TypeID::Var(100)).unwrap().clone(),
-                    dst_type: σ.get(&TypeID::Var(101)).unwrap().clone(),
-                }.normalize();
-
-                //eprintln!("Map Morph: try to find item-morph with type {:?}", item_morph_type);
-                if let Some(item_morph_inst) = self.find_morphism( &item_morph_type, dict ) {
-                    if let Some( list_morph ) = item_morph_inst.m.map_morphism( seq_type.clone() ) {
-                        return Some( MorphismInstance {
-                            m: list_morph,
-                            σ,
-                            halo: halos[0].clone()
-                        } );
-                    }
-                }
+            /* 2. check complex types */
+            else if let Some(complex_morph) = self.complex_morphism_decomposition(src_type, &m_src_type) {
+                //eprintln!("found complex morph to {:?}", complex_morph.get_type().dst_type);
+                morphs.push(complex_morph);
             }
         }
 
-        None
+        morphs
     }
 
-    pub fn find_morphism(&self, ty: &MorphismType,
-        dict: &mut impl TypeDict
-    )
-    -> Option< MorphismInstance<M> > {
-        if let Some(m) = self.find_direct_morphism(ty, dict) {
-            return Some(m);
+
+    pub fn to_dot(&self, dict: &mut impl TypeDict) -> String {
+        let mut dot_source = String::new();
+
+        dot_source.push_str("digraph MorphismGraph {");
+
+        pub fn ty_to_dot_label(dict: &mut impl TypeDict, ty: &TypeTerm) -> String {
+            let pretty_str = ty.pretty(dict, 0);
+            let mut child = std::process::Command::new("aha").arg("--no-header")
+                .stdin( std::process::Stdio::piped() )
+                .stdout(std::process::Stdio::piped())
+                .spawn().expect("spawn child");
+            let mut stdin = child.stdin.take().expect("cant get stdin");
+            std::thread::spawn(move ||{ stdin.write_all(pretty_str.as_bytes()).expect("failed to write")});
+            let out = child.wait_with_output().expect("");
+            let html_str = String::from_utf8_lossy(&out.stdout).replace("\n", "<BR/>").replace("span", "B");
+            html_str
         }
-        if let Some(m) = self.find_map_morphism(ty, dict) {
-            return Some(m);
+
+        // add vertices
+        for (i,m) in self.morphisms.iter().enumerate() {
+            dot_source.push_str(&format!("
+                SRC{} [label=<{}>]
+                DST{} [label=<{}>]
+
+                SRC{} -> DST{} [label=\"{}\"]
+            ", i, ty_to_dot_label(dict, &m.get_type().src_type),
+                i, ty_to_dot_label(dict, &m.get_type().dst_type),
+                i,i,i
+            ));
         }
-        None
+
+        // add edges
+
+
+        dot_source.push_str("}");
+
+        dot_source
     }
+
 }
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/morphism_base_sugared.rs b/src/morphism_base_sugared.rs
deleted file mode 100644
index 23720c7..0000000
--- a/src/morphism_base_sugared.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-use {
-    crate::{
-        morphism_path_sugared::{SugaredMorphismPath, SugaredShortestPathProblem}, morphism_sugared::{MorphismInstance2, SugaredMorphism, SugaredMorphismType}, sugar::SugaredTypeTerm, SugaredStructMember, TypeDict, TypeID, TypeTerm
-    }
-};
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone)]
-pub struct SugaredMorphismBase<M: SugaredMorphism + Clone> {
-    morphisms: Vec< M >
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-impl<M: SugaredMorphism + Clone> SugaredMorphismBase<M> {
-    pub fn new() -> Self {
-        SugaredMorphismBase {
-            morphisms: Vec::new()
-        }
-    }
-
-    pub fn add_morphism(&mut self, m: M) {
-        self.morphisms.push( m );
-    }
-
-    pub fn get_morphism_instance(&self, ty: &SugaredMorphismType) -> Option<MorphismInstance2<M>> {
-        if let Some(path) = SugaredShortestPathProblem::new(self, ty.clone()).solve() {
-            if path.len() == 1 {
-                Some(path[0].clone())
-            } else {
-                Some(MorphismInstance2::Chain { path })
-            }
-        } else {
-            None
-        }
-    }
-
-    pub fn complex_morphism_decomposition(&self, src_type: &SugaredTypeTerm, dst_type: &SugaredTypeTerm) -> Option< MorphismInstance2<M> > {
-        let (src_ψ, src_floor) = src_type.get_floor_type();
-        let (dst_ψ, dst_floor) = dst_type.get_floor_type();
-
-        if !dst_ψ.is_empty() {
-            if !crate::unification_sugared::subtype_unify(&src_ψ, &dst_ψ).is_ok() {
-                return None;
-            }
-        }
-
-        match (src_floor, dst_floor) {
-            (SugaredTypeTerm::Struct{ struct_repr: struct_repr_lhs, members: members_lhs},
-                SugaredTypeTerm::Struct { struct_repr: struct_repr_rhs, members: members_rhs })
-            => {
-                // todo: optimization: check if struct repr match
-
-                let mut member_morph = Vec::new();
-                let mut failed = false;
-                let mut necessary = false;
-
-                for SugaredStructMember{ symbol: symbol_rhs, ty: ty_rhs } in members_rhs.iter() {
-                    let mut found_src_member = false;
-                    for SugaredStructMember{ symbol: symbol_lhs, ty: ty_lhs } in members_lhs.iter() {
-                        if symbol_rhs == symbol_lhs {
-                            found_src_member = true;
-
-                            if let Some(mm) = self.get_morphism_instance(&SugaredMorphismType { src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) {
-                                if ty_lhs != ty_rhs {
-                                    necessary = true;
-                                }
-                                member_morph.push((symbol_lhs.clone(), mm))
-                            } else {
-                                failed = true;
-                            }
-                            break;
-                        }
-                    }
-
-                    // member of rhs not found in lhs
-                    if ! found_src_member {
-                        failed = true;
-                        break;
-                    }
-                }
-
-                if ! failed && necessary {
-                    Some(MorphismInstance2::MapStruct {
-                        ψ: src_ψ,
-                        src_struct_repr: struct_repr_lhs.clone(),
-                        dst_struct_repr: struct_repr_rhs.clone(),
-                        member_morph
-                    })
-                } else {
-                    None
-                }
-            }
-
-
-            (SugaredTypeTerm::Seq{ seq_repr: seq_repr_lhs, items: items_lhs },
-                SugaredTypeTerm::Seq{ seq_repr: _seq_rerpr_rhs, items: items_rhs })
-            => {
-                //let mut item_morphs = Vec::new();
-
-                for (ty_lhs, ty_rhs) in items_lhs.iter().zip(items_rhs.iter()) {
-                    if let Some(item_morph) = self.get_morphism_instance(&SugaredMorphismType{ src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) {
-                        return Some(MorphismInstance2::MapSeq { ψ: src_ψ, seq_repr: seq_repr_lhs.clone(), item_morph: Box::new(item_morph) });
-                    }
-                    break;
-                }
-                None
-            }
-
-            _ => {
-                None
-            }
-        }
-    }
-
-    pub fn enum_morphisms_from(&self, src_type: &SugaredTypeTerm) -> Vec< MorphismInstance2<M> > {
-        let mut morphs = Vec::new();
-
-        for m in self.morphisms.iter() {
-            let m_src_type = m.get_type().src_type;
-            let m_dst_type = m.get_type().dst_type;
-
-            /* 1. primitive morphisms */
-
-            // check if the given start type is compatible with the
-            // morphisms source type,
-            // i.e. check if `src_type` is a subtype of `m_src_type`
-            if let Ok((ψ, σ)) = crate::unification_sugared::subtype_unify(src_type, &m_src_type) {
-                let morph_inst = MorphismInstance2::Primitive { ψ, σ, morph: m.clone() };
-                //eprintln!("..found direct morph to {:?}", morph_inst.get_type().dst_type);
-                morphs.push(morph_inst);
-            }
-
-            /* 2. check complex types */
-            else if let Some(complex_morph) = self.complex_morphism_decomposition(src_type, &m_src_type) {
-                //eprintln!("found complex morph to {:?}", complex_morph.get_type().dst_type);
-                morphs.push(complex_morph);
-            }
-        }
-
-        morphs
-    }
-
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/morphism_path.rs b/src/morphism_path.rs
index c67e0cc..d7af60a 100644
--- a/src/morphism_path.rs
+++ b/src/morphism_path.rs
@@ -1,9 +1,10 @@
 use {
     crate::{
-        morphism::{MorphismType, Morphism, MorphismInstance},
-        morphism_base::MorphismBase,
         dict::*,
-        term::*
+        morphism::{Morphism, MorphismType, MorphismInstance},
+        morphism_base::MorphismBase,
+        substitution::Substitution,
+        term::*, desugared_term::*,
     }
 };
 
@@ -16,6 +17,15 @@ pub struct MorphismPath<M: Morphism + Clone> {
     pub morphisms: Vec< MorphismInstance<M> >
 }
 
+
+impl<M: Morphism+Clone> MorphismPath<M> {
+    fn apply_subst(&mut self, σ: &std::collections::HashMap<TypeID, TypeTerm>) {
+        for m in self.morphisms.iter_mut() {
+            m.apply_subst(σ);
+        }
+    }
+}
+
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 pub struct ShortestPathProblem<'a, M: Morphism + Clone> {
@@ -37,107 +47,55 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> {
         }
     }
 
+    pub fn advance(&mut self, prev_path: &MorphismPath<M>, morph_inst: MorphismInstance<M>) {
+        let dst_type = morph_inst.get_type().dst_type;
+        //eprintln!("try morph to {:?}", dst_type.clone());//.sugar(type_dict).pretty(type_dict, 0));
+
+        let mut creates_loop = false;
+
+        let mut new_path = prev_path.clone();
+        new_path.apply_subst(&morph_inst.get_subst());
+        for m in new_path.morphisms.iter() {
+            if m.get_type().src_type == dst_type {
+                creates_loop = true;
+                break;
+            }
+        }
+
+        if ! creates_loop {
+            new_path.weight += 1;//next_morph_inst.get_weight();
+            new_path.cur_type = dst_type;
+
+            new_path.morphisms.push(morph_inst);
+            self.queue.push(new_path);
+        }
+    }
+
     pub fn solve(&mut self) -> Option< Vec<MorphismInstance<M>> > {
         while ! self.queue.is_empty() {
             /* take the shortest partial path and try to advance it by one step */
             self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight));
-
             if let Some(mut cur_path) = self.queue.pop() {
 
                 /* 1. Check if goal is already reached by the current path */
-
-                if let Ok((ψ, σ)) = crate::unification::subtype_unify( &cur_path.cur_type, &self.goal ) {
+                if let Ok((_ψ, σ)) = crate::constraint_system::subtype_unify( &cur_path.cur_type, &self.goal ) {
                     /* found path,
                      * now apply substitution and trim to variables in terms of each step
                      */
-                    for n in cur_path.morphisms.iter_mut() {
-                        let src_type = n.m.get_type().src_type;
-                        let dst_type = n.m.get_type().dst_type;
-
-                        let mut new_σ = std::collections::HashMap::new();
-                        for (k,v) in σ.iter() {
-                            if let TypeID::Var(varid) = k {
-                                if src_type.contains_var(*varid)
-                                || dst_type.contains_var(*varid) {
-                                    new_σ.insert(
-                                        k.clone(),
-                                        v.clone().apply_subst(&σ).clone().strip()
-                                    );
-                                }
-                            }
-                        }
-                        for (k,v) in n.σ.iter() {
-                            if let TypeID::Var(varid) = k {
-                                if src_type.contains_var(*varid)
-                                || dst_type.contains_var(*varid) {
-                                    new_σ.insert( k.clone(), v.clone().apply_subst(&σ).clone().strip() );
-                                }
-                            }
-                        }
-
-                        n.halo = n.halo.clone().apply_subst(&σ).clone().strip().param_normalize();
-                        n.σ = new_σ;
-                    }
-
+                    cur_path.apply_subst(&σ);
                     return Some(cur_path.morphisms);
                 }
 
-                /* 2. Try to advance the path */
-                /* 2.1. Direct Morphisms */
-
-                //eprintln!("cur path (w ={}) : @ {:?}", cur_path.weight, cur_path.cur_type);//.clone().sugar(type_dict).pretty(type_dict, 0) );
-                for mut next_morph_inst in self.morphism_base.enum_morphisms(&cur_path.cur_type) {
-                    let dst_type = next_morph_inst.get_type().dst_type;
-//                    eprintln!("try morph to {}", dst_type.clone().sugar(type_dict).pretty(type_dict, 0));
-
-                    let mut creates_loop = false;
-
-                    let mut new_path = cur_path.clone();
-                    for n in new_path.morphisms.iter_mut() {
-                        let mut new_σ = std::collections::HashMap::new();
-
-                        for (k,v) in next_morph_inst.σ.iter() {
-                            new_σ.insert(
-                                k.clone(),
-                                v.clone().apply_subst(&next_morph_inst.σ).clone()
-                            );
-                        }
-
-                        for (k,v) in n.σ.iter() {
-                            new_σ.insert(
-                                k.clone(),
-                                v.clone().apply_subst(&next_morph_inst.σ).clone()
-                            );
-                        }
-
-                        n.halo = n.halo.clone()
-                            .apply_subst( &next_morph_inst.σ ).clone()
-                            .strip().param_normalize();
-
-                        n.σ = new_σ;
-                    }
-
-                    for m in new_path.morphisms.iter() {
-                        if m.get_type().src_type == dst_type {
-                            creates_loop = true;
-                            break;
-                        }
-                    }
-
-                    if ! creates_loop {
-                        new_path.weight += next_morph_inst.m.weight();
-                        new_path.cur_type = dst_type;
-
-                        new_path.morphisms.push(next_morph_inst);
-                        self.queue.push(new_path);
-                    }
+                /* 2. Try to advance current path */
+                else if let Some(complex_morph) =
+                    self.morphism_base.complex_morphism_decomposition( &cur_path.cur_type, &self.goal )
+                {
+                    self.advance(&cur_path, complex_morph);
                 }
 
-                /* 2.2. Try to decompose */
-                /* 2.2.1.  Seq - Map */
-                /* 2.2.2.  Struct - Map */
-                /* 2.2.3.  Enum - Map */
-
+                for next_morph_inst in self.morphism_base.enum_morphisms_from(&cur_path.cur_type) {
+                    self.advance(&cur_path, next_morph_inst);
+                }
             }
         }
         None
diff --git a/src/morphism_path_sugared.rs b/src/morphism_path_sugared.rs
deleted file mode 100644
index 3f6fe77..0000000
--- a/src/morphism_path_sugared.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-use {
-    crate::{
-        dict::*,
-        morphism_sugared::{SugaredMorphism, SugaredMorphismType, MorphismInstance2},
-        morphism_base_sugared::SugaredMorphismBase,
-        substitution_sugared::SugaredSubstitution,
-        sugar::*, term::*,
-    }
-};
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone)]
-pub struct SugaredMorphismPath<M: SugaredMorphism + Clone> {
-    pub weight: u64,
-    pub cur_type: SugaredTypeTerm,
-    pub morphisms: Vec< MorphismInstance2<M> >
-}
-
-
-impl<M: SugaredMorphism+Clone> SugaredMorphismPath<M> {
-    fn apply_subst(&mut self, σ: &std::collections::HashMap<TypeID, SugaredTypeTerm>) {
-        for m in self.morphisms.iter_mut() {
-            m.apply_subst(σ);
-        }
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-pub struct SugaredShortestPathProblem<'a, M: SugaredMorphism + Clone> {
-    pub morphism_base: &'a SugaredMorphismBase<M>,
-    pub goal: SugaredTypeTerm,
-    queue: Vec< SugaredMorphismPath<M> >
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-impl<'a, M:SugaredMorphism+Clone> SugaredShortestPathProblem<'a, M> {
-    pub fn new(morphism_base: &'a SugaredMorphismBase<M>, ty: SugaredMorphismType) -> Self {
-        SugaredShortestPathProblem {
-            morphism_base,
-            queue: vec![
-                SugaredMorphismPath::<M> { weight: 0, cur_type: ty.src_type, morphisms: vec![] }
-            ],
-            goal: ty.dst_type
-        }
-    }
-
-    pub fn advance(&mut self, prev_path: &SugaredMorphismPath<M>, morph_inst: MorphismInstance2<M>) {
-        let dst_type = morph_inst.get_type().dst_type;
-        //eprintln!("try morph to {:?}", dst_type.clone());//.sugar(type_dict).pretty(type_dict, 0));
-
-        let mut creates_loop = false;
-
-        let mut new_path = prev_path.clone();
-        new_path.apply_subst(&morph_inst.get_subst());
-        for m in new_path.morphisms.iter() {
-            if m.get_type().src_type == dst_type {
-                creates_loop = true;
-                break;
-            }
-        }
-
-        if ! creates_loop {
-            new_path.weight += 1;//next_morph_inst.get_weight();
-            new_path.cur_type = dst_type;
-
-            new_path.morphisms.push(morph_inst);
-            self.queue.push(new_path);
-        }
-    }
-
-    pub fn solve(&mut self) -> Option< Vec<MorphismInstance2<M>> > {
-        while ! self.queue.is_empty() {
-            /* take the shortest partial path and try to advance it by one step */
-            self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight));
-            if let Some(mut cur_path) = self.queue.pop() {
-
-                /* 1. Check if goal is already reached by the current path */
-                if let Ok((_ψ, σ)) = crate::unification_sugared::subtype_unify( &cur_path.cur_type, &self.goal ) {
-                    /* found path,
-                     * now apply substitution and trim to variables in terms of each step
-                     */
-                    cur_path.apply_subst(&σ);
-                    return Some(cur_path.morphisms);
-                }
-
-                /* 2. Try to advance current path */
-                else if let Some(complex_morph) =
-                    self.morphism_base.complex_morphism_decomposition( &cur_path.cur_type, &self.goal )
-                {
-                    self.advance(&cur_path, complex_morph);
-                }
-
-                for next_morph_inst in self.morphism_base.enum_morphisms_from(&cur_path.cur_type) {
-                    self.advance(&cur_path, next_morph_inst);
-                }
-            }
-        }
-        None
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/morphism_sugared.rs b/src/morphism_sugared.rs
deleted file mode 100644
index 2b5684d..0000000
--- a/src/morphism_sugared.rs
+++ /dev/null
@@ -1,380 +0,0 @@
-use {
-    crate::{
-        substitution_sugared::SugaredSubstitution, sugar::{SugaredStructMember, SugaredTypeTerm}, unification::UnificationProblem, unification_sugared::SugaredUnificationProblem, unparser::*, SugaredEnumVariant, TypeDict, TypeID, TypeTerm
-    },
-    std::{collections::HashMap, u64}
-};
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct SugaredMorphismType {
-    pub src_type: SugaredTypeTerm,
-    pub dst_type: SugaredTypeTerm
-}
-
-impl SugaredMorphismType {
-    pub fn strip_halo(&self) -> SugaredMorphismType {
-        match (&self.src_type.clone().strip(), &self.dst_type.clone().strip()) {
-            (SugaredTypeTerm::Ladder(rungs_lhs), SugaredTypeTerm::Ladder(rungs_rhs)) => {
-
-                let mut lhs_iter = rungs_lhs.iter();
-                let mut rhs_iter = rungs_rhs.iter();
-                let mut last = SugaredMorphismType { src_type: SugaredTypeTerm::unit(), dst_type: SugaredTypeTerm::unit() };
-
-                while let (Some(lhs_top), Some(rhs_top)) = (lhs_iter.next(), rhs_iter.next()) {
-                    last = SugaredMorphismType{
-                        src_type: lhs_top.clone(),
-                        dst_type: rhs_top.clone()
-                    };
-
-                    if lhs_top != rhs_top {
-                        let x = SugaredMorphismType{ src_type: lhs_top.clone(), dst_type: rhs_top.clone() }.strip_halo();
-
-                        let mut rl : Vec<_> = lhs_iter.cloned().collect();
-                        rl.insert(0, x.src_type);
-                        let mut rr : Vec<_> = rhs_iter.cloned().collect();
-                        rr.insert(0, x.dst_type);
-
-                        return SugaredMorphismType {
-                            src_type: SugaredTypeTerm::Ladder(rl),
-                            dst_type: SugaredTypeTerm::Ladder(rr)
-                        };
-                    }
-                }
-
-                last
-            }
-
-            (SugaredTypeTerm::Spec(args_lhs), SugaredTypeTerm::Spec(args_rhs)) => {
-
-                let (rl, rr) = args_lhs.iter().zip(args_rhs.iter()).map(
-                    |(al,ar)| SugaredMorphismType{ src_type: al.clone(), dst_type: ar.clone() }.strip_halo()
-                )
-                .fold((vec![], vec![]), |(mut rl, mut rr), x| {
-                    rl.push(x.src_type);
-                    rr.push(x.dst_type);
-                    (rl,rr)
-                });
-
-                SugaredMorphismType {
-                    src_type: SugaredTypeTerm::Spec(rl),
-                    dst_type: SugaredTypeTerm::Spec(rr)
-                }
-            }
-
-            (SugaredTypeTerm::Seq { seq_repr:seq_repr_lhs, items:items_lhs },
-                SugaredTypeTerm::Seq { seq_repr: seq_repr_rhs, items:items_rhs })
-            => {
-                let (rl, rr) = items_lhs.iter().zip(items_rhs.iter()).map(
-                    |(al,ar)| SugaredMorphismType{ src_type: al.clone(), dst_type: ar.clone() }.strip_halo()
-                )
-                .fold((vec![], vec![]), |(mut rl, mut rr), x| {
-                    rl.push(x.src_type);
-                    rr.push(x.dst_type);
-                    (rl,rr)
-                });
-                SugaredMorphismType  {
-                    src_type: SugaredTypeTerm::Seq{ seq_repr: seq_repr_lhs.clone(), items: rl },
-                    dst_type: SugaredTypeTerm::Seq { seq_repr: seq_repr_rhs.clone(), items: rr }
-                }
-            }
-
-            (SugaredTypeTerm::Struct { struct_repr:struct_repr_lhs, members:members_lhs },
-                SugaredTypeTerm::Struct { struct_repr: struct_repr_rhs, members:members_rhs })
-            => {
-                let mut rl = Vec::new();
-                let mut rr = Vec::new();
-
-                for ar in members_rhs.iter() {
-                    let mut found = false;
-                    for al in members_lhs.iter() {
-                        if al.symbol == ar.symbol {
-                            let x = SugaredMorphismType{ src_type: al.ty.clone(), dst_type: ar.ty.clone() }.strip_halo();
-                            rl.push( SugaredStructMember{
-                                symbol: al.symbol.clone(),
-                                ty: x.src_type
-                            });
-                            rr.push( SugaredStructMember{
-                                symbol: ar.symbol.clone(),
-                                ty: x.dst_type
-                            });
-                            found = true;
-                            break;
-                        }
-                    }
-
-                    if !found {
-                        return SugaredMorphismType {
-                            src_type: SugaredTypeTerm::Struct { struct_repr: struct_repr_lhs.clone(), members:members_lhs.clone() },
-                            dst_type: SugaredTypeTerm::Struct { struct_repr: struct_repr_rhs.clone(), members:members_rhs.clone() }
-                        };
-                    }
-                }
-
-                SugaredMorphismType  {
-                    src_type: SugaredTypeTerm::Struct{ struct_repr: struct_repr_lhs.clone(), members: rl },
-                    dst_type: SugaredTypeTerm::Struct{ struct_repr: struct_repr_rhs.clone(), members: rr }
-                }
-            }
-
-            (SugaredTypeTerm::Enum { enum_repr:enum_repr_lhs, variants:variants_lhs },
-                SugaredTypeTerm::Enum { enum_repr: enum_repr_rhs, variants:variants_rhs })
-            => {
-                let mut rl = Vec::new();
-                let mut rr = Vec::new();
-
-                for ar in variants_rhs.iter() {
-                    let mut found = false;
-                    for al in variants_lhs.iter() {
-                        if al.symbol == ar.symbol {
-                            let x = SugaredMorphismType{ src_type: al.ty.clone(), dst_type: ar.ty.clone() }.strip_halo();
-                            rl.push( SugaredEnumVariant{
-                                symbol: al.symbol.clone(),
-                                ty: x.src_type
-                            });
-                            rr.push( SugaredEnumVariant{
-                                symbol: ar.symbol.clone(),
-                                ty: x.dst_type
-                            });
-                            found = true;
-                            break;
-                        }
-                    }
-
-                    if !found {
-                        return SugaredMorphismType {
-                            src_type: SugaredTypeTerm::Enum { enum_repr: enum_repr_lhs.clone(), variants:variants_lhs.clone() },
-                            dst_type: SugaredTypeTerm::Enum { enum_repr: enum_repr_rhs.clone(), variants:variants_rhs.clone() }
-                        };
-                    }
-                }
-
-                SugaredMorphismType  {
-                    src_type: SugaredTypeTerm::Enum{ enum_repr: enum_repr_lhs.clone(), variants: rl },
-                    dst_type: SugaredTypeTerm::Enum { enum_repr: enum_repr_rhs.clone(), variants: rr }
-                }
-            }
-
-            (x,y) => SugaredMorphismType { src_type: x.clone(), dst_type: y.clone() }
-        }
-    }
-
-    pub fn apply_subst(&self, σ: &impl SugaredSubstitution) -> SugaredMorphismType {
-        SugaredMorphismType {
-            src_type: self.src_type.clone().apply_subst(σ).clone(),
-            dst_type: self.dst_type.clone().apply_subst(σ).clone()
-        }
-    }
-
-
-    pub fn normalize(&self) -> SugaredMorphismType {
-        SugaredMorphismType {
-            src_type: self.src_type.clone().normalize(),
-            dst_type: self.dst_type.clone().normalize(),
-        }
-    }
-}
-
-pub trait SugaredMorphism : Sized {
-    fn get_type(&self) -> SugaredMorphismType;
-    fn weight(&self) -> u64 {
-        1
-    }
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum MorphismInstance2<M: SugaredMorphism + Clone> {
-    Primitive{
-        ψ: SugaredTypeTerm,
-        σ: HashMap<TypeID, SugaredTypeTerm>,
-        morph: M,
-    },
-    Chain{
-        path: Vec<MorphismInstance2<M>>
-    },
-    MapSeq{
-        ψ: SugaredTypeTerm,
-        seq_repr: Option<Box<SugaredTypeTerm>>,
-        item_morph: Box<MorphismInstance2<M>>,
-    },
-    MapStruct{
-        ψ: SugaredTypeTerm,
-        src_struct_repr: Option<Box<SugaredTypeTerm>>,
-        dst_struct_repr: Option<Box<SugaredTypeTerm>>,
-        member_morph: Vec< (String, MorphismInstance2<M>) >
-    },
-    MapEnum{
-        ψ: SugaredTypeTerm,
-        enum_repr: Option<Box<SugaredTypeTerm>>,
-        variant_morph: Vec< (String, MorphismInstance2<M>) >
-    }
-}
-
-
-impl<M: SugaredMorphism + Clone> MorphismInstance2<M> {
-    pub fn get_haloless_type(&self) -> SugaredMorphismType {
-        self.get_type().strip_halo()
-    }
-
-    pub fn get_type(&self) -> SugaredMorphismType {
-        match self {
-            MorphismInstance2::Primitive { ψ, σ, morph } => {
-                SugaredMorphismType {
-                    src_type:
-                        SugaredTypeTerm::Ladder(vec![
-                            ψ.clone(),
-                            morph.get_type().src_type
-                                .apply_subst(σ).clone()
-                        ]).strip(),
-
-                    dst_type: SugaredTypeTerm::Ladder(vec![
-                            ψ.clone(),
-                            morph.get_type().dst_type
-                                .apply_subst(σ).clone()
-                        ]).strip(),
-                }
-            }
-            MorphismInstance2::Chain { path } => {
-                if path.len() > 0 {
-                    let s = self.get_subst();
-                    SugaredMorphismType {
-                        src_type: path.first().unwrap().get_type().src_type.clone(),
-                        dst_type: path.last().unwrap().get_type().dst_type.clone()
-                    }.apply_subst(&s)
-                } else {
-                    SugaredMorphismType {
-                        src_type: SugaredTypeTerm::TypeID(TypeID::Fun(45454)),
-                        dst_type: SugaredTypeTerm::TypeID(TypeID::Fun(45454))
-                    }
-                }
-            }
-            MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => {
-                SugaredMorphismType {
-                    src_type: SugaredTypeTerm::Ladder(vec![
-                        ψ.clone(),
-                        SugaredTypeTerm::Seq{ seq_repr: seq_repr.clone(),
-                            items: vec![ item_morph.get_type().src_type ]}
-                    ]),
-                    dst_type: SugaredTypeTerm::Ladder(vec![
-                        ψ.clone(),
-                        SugaredTypeTerm::Seq{ seq_repr: seq_repr.clone(),
-                            items: vec![ item_morph.get_type().dst_type ]}
-                    ])
-                }
-            }
-            MorphismInstance2::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
-                SugaredMorphismType {
-                    src_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(),
-                            SugaredTypeTerm::Struct{
-                                struct_repr: src_struct_repr.clone(),
-                                members:
-                                    member_morph.iter().map(|(symbol, morph)| {
-                                       SugaredStructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
-                                    }).collect()
-                            }
-                        ]),
-                    dst_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(),
-                            SugaredTypeTerm::Struct{
-                                struct_repr: dst_struct_repr.clone(),
-                                members: member_morph.iter().map(|(symbol, morph)| {
-                                    SugaredStructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
-                                }).collect()
-                            }
-                        ])
-                }
-            }
-            MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => {
-                SugaredMorphismType {
-                    src_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(),
-                            SugaredTypeTerm::Struct{
-                                struct_repr: enum_repr.clone(),
-                                members:
-                                    variant_morph.iter().map(|(symbol, morph)| {
-                                       SugaredStructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
-                                    }).collect()
-                            }
-                        ]),
-                    dst_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(),
-                            SugaredTypeTerm::Struct{
-                                struct_repr: enum_repr.clone(),
-                                members: variant_morph.iter().map(|(symbol, morph)| {
-                                    SugaredStructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
-                                }).collect()
-                            }
-                        ])
-                }
-            }
-        }.normalize()
-    }
-
-    pub fn get_subst(&self) -> std::collections::HashMap< TypeID, SugaredTypeTerm > {
-        match self {
-            MorphismInstance2::Primitive { ψ, σ, morph } => σ.clone(),
-            MorphismInstance2::Chain { path } => {
-                path.iter().fold(
-                    std::collections::HashMap::new(),
-                    |mut σ, m| {
-                        σ = σ.append(&m.get_subst());
-                        σ
-                    }
-                )
-            },
-            MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => {
-                item_morph.get_subst()
-            },
-            MorphismInstance2::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
-                let mut σ = HashMap::new();
-                for (symbol, m) in member_morph.iter() {
-                    σ = σ.append(&mut m.get_subst());
-                }
-                σ
-            },
-            MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => {
-                todo!();
-                HashMap::new()
-            },
-        }
-    }
-
-    pub fn apply_subst(&mut self, γ: &std::collections::HashMap< TypeID, SugaredTypeTerm >) {
-        let ty = self.get_type();
-        match self {
-            MorphismInstance2::Primitive { ψ, σ, morph } => {
-                ψ.apply_subst(γ);
-                for (n,t) in σ.iter_mut() {
-                    t.apply_subst(γ);
-                }
-                for (n,t) in γ.iter() {
-                    if let TypeID::Var(varid) = n {
-                        if morph.get_type().src_type.apply_subst(σ).contains_var(*varid)
-                        || morph.get_type().dst_type.apply_subst(σ).contains_var(*varid) {
-                            σ.insert(n.clone(), t.clone());
-                        }
-                    }
-                }
-            },
-            MorphismInstance2::Chain { path } => {
-                for n in path.iter_mut() {
-                    n.apply_subst(γ);
-                }
-            }
-            MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => {
-                ψ.apply_subst(γ);
-                item_morph.apply_subst(γ);
-            }
-            MorphismInstance2::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
-                for (_,ty) in member_morph {
-                    ty.apply_subst(γ);
-                }
-            },
-            MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => {
-                for (_,ty) in variant_morph {
-                    ty.apply_subst(γ);
-                }
-            }
-        }
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/parser.rs b/src/parser.rs
index 6160ca6..4d6a21e 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,10 +1,8 @@
 use {
-    std::iter::Peekable,
     crate::{
-        dict::*,
-        term::*,
-        lexer::*
-    }
+        dict::*, lexer::*, desugared_term::*, TypeTerm, term::*
+
+    }, std::iter::Peekable
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
@@ -19,22 +17,28 @@ pub enum ParseError {
 }
 
 pub trait ParseLadderType {
-    fn parse(&mut self, s: &str) -> Result<TypeTerm, ParseError>;
-    
-    fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse(&mut self, s:&str) -> Result<TypeTerm, ParseError>;
+
+    fn parse_desugared(&mut self, s: &str) -> Result<DesugaredTypeTerm, ParseError>;
+
+    fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>;
 
-    fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>;
 
-    fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>;
 }
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 impl<T: TypeDict> ParseLadderType for T {
-    fn parse(&mut self, s: &str) -> Result<TypeTerm, ParseError> {
+    fn parse(&mut self, s:&str) -> Result<TypeTerm, ParseError> {
+        Ok(self.parse_desugared(s)?.sugar(self))
+    }
+
+    fn parse_desugared(&mut self, s: &str) -> Result<DesugaredTypeTerm, ParseError> {
         let mut tokens = LadderTypeLexer::from(s.chars()).peekable();
 
         match self.parse_ladder(&mut tokens) {
@@ -49,7 +53,7 @@ impl<T: TypeDict> ParseLadderType for T {
         }
     }
 
-    fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>
     {
         let mut args = Vec::new();
@@ -57,7 +61,7 @@ impl<T: TypeDict> ParseLadderType for T {
             match tok {
                 Ok(LadderTypeToken::Close) => {
                     tokens.next();
-                    return Ok(TypeTerm::App(args));
+                    return Ok(DesugaredTypeTerm::App(args));
                 }
                 _ => {
                     match self.parse_ladder(tokens) {
@@ -70,7 +74,7 @@ impl<T: TypeDict> ParseLadderType for T {
         Err(ParseError::UnexpectedEnd)
     }
 
-    fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>
     {
         match tokens.next() {
@@ -78,21 +82,21 @@ impl<T: TypeDict> ParseLadderType for T {
             Some(Ok(LadderTypeToken::Close)) => Err(ParseError::UnexpectedClose),
             Some(Ok(LadderTypeToken::Ladder)) => Err(ParseError::UnexpectedLadder),
             Some(Ok(LadderTypeToken::Symbol(s))) =>
-                Ok(TypeTerm::TypeID(
+                Ok(DesugaredTypeTerm::TypeID(
                     if let Some(tyid) = self.get_typeid(&s) {
                         tyid
                     } else {
                         self.add_typename(s)
                     }
                 )),
-            Some(Ok(LadderTypeToken::Char(c))) => Ok(TypeTerm::Char(c)),
-            Some(Ok(LadderTypeToken::Num(n))) => Ok(TypeTerm::Num(n)),
+            Some(Ok(LadderTypeToken::Char(c))) => Ok(DesugaredTypeTerm::Char(c)),
+            Some(Ok(LadderTypeToken::Num(n))) => Ok(DesugaredTypeTerm::Num(n)),
             Some(Err(err)) => Err(ParseError::LexError(err)),
             None => Err(ParseError::UnexpectedEnd)
         }
     }
 
-    fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError>
+    fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<DesugaredTypeTerm, ParseError>
     where It: Iterator<Item = char>
     {
         let mut rungs = Vec::new();
@@ -101,7 +105,7 @@ impl<T: TypeDict> ParseLadderType for T {
             Ok(t) => { rungs.push(t); }
             Err(err) => { return Err(err); }
         }
-        
+
         while let Some(tok) = tokens.peek() {
             match tok {
                 Ok(LadderTypeToken::Ladder) => {
@@ -113,7 +117,7 @@ impl<T: TypeDict> ParseLadderType for T {
                             Err(err) => { return Err(err); }
                         }
                     } else {
-                        return Err(ParseError::UnexpectedLadder);    
+                        return Err(ParseError::UnexpectedLadder);
                     }
                 }
                 Err(lexerr) => {
@@ -128,7 +132,7 @@ impl<T: TypeDict> ParseLadderType for T {
         match rungs.len() {
             0 => Err(ParseError::UnexpectedEnd),
             1 => Ok(rungs[0].clone()),
-            _ => Ok(TypeTerm::Ladder(rungs)),
+            _ => Ok(DesugaredTypeTerm::Ladder(rungs)),
         }
     }
 }
diff --git a/src/pnf.rs b/src/pnf.rs
index d3a6b20..ba4a24f 100644
--- a/src/pnf.rs
+++ b/src/pnf.rs
@@ -1,8 +1,10 @@
-use crate::term::TypeTerm;
+use crate::{term::TypeTerm, constraint_system, EnumVariant, StructMember};
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 pub fn splice_ladders( mut upper: Vec< TypeTerm >, mut lower: Vec< TypeTerm >  ) -> Vec< TypeTerm > {
+    eprintln!("splice ladders {:?} <<<====>>>  {:?} ", upper, lower);
+    // check for overlap
     for i in 0 .. upper.len() {
         if upper[i] == lower[0] {
             let mut result_ladder = Vec::<TypeTerm>::new();
@@ -12,6 +14,7 @@ pub fn splice_ladders( mut upper: Vec< TypeTerm >, mut lower: Vec< TypeTerm >  )
         }
     }
 
+    // no overlap found, just concatenate ladders
     upper.append(&mut lower);
     upper
 }
@@ -24,112 +27,305 @@ impl TypeTerm {
     /// <Seq <Digit 10>>~<Seq Char>
     /// ⇒ <Seq <Digit 10>~Char>
     /// ```
-    pub fn param_normalize(mut self) -> Self {
+    pub fn normalize(mut self) -> Self {
         match self {
             TypeTerm::Ladder(mut rungs) => {
-                if rungs.len() > 0 {
-                    let mut new_rungs = Vec::new();
-                    while let Some(bottom) = rungs.pop() {
-                        if let Some(last_but) = rungs.last_mut() {
-                            match (bottom, last_but) {
-                                (TypeTerm::App(bot_args), TypeTerm::App(last_args)) => {
-                                    if bot_args.len() == last_args.len() {
-                                        let mut new_rung_params = Vec::new();
-                                        let mut require_break = false;
+                if rungs.len() == 0 {
+                    return TypeTerm::unit();
+                } else if rungs.len() == 1 {
+                    return rungs.pop().unwrap().normalize();
+                }
 
-                                        if bot_args.len() > 0 {
-                                            if let Ok(_idx) =  last_args[0].is_syntactic_subtype_of(&bot_args[0]) {
-                                                for i in 0 .. bot_args.len() {
+                let mut new_rungs = Vec::new();
+                let mut r2 = rungs.pop().unwrap().strip();
+                while let Some(r1) = rungs.pop() {
+                    let r1 = r1.strip();
+                    match (r1.clone(), r2.clone()) {
+                        (TypeTerm::Seq { seq_repr: seq_repr1, items: items1 },
+                         TypeTerm::Seq { seq_repr: seq_repr2, items: items2 })
+                        => {
+                            r2 = TypeTerm::Seq {
+                                    seq_repr:
+                                        if seq_repr1.is_some() || seq_repr2.is_some() {
+                                            let sr1 = if let Some(seq_repr1) = seq_repr1 { *seq_repr1.clone() }
+                                                        else { TypeTerm::unit() };
+                                            let sr2 = if let Some(seq_repr2) = seq_repr2 { *seq_repr2 }
+                                                        else { TypeTerm::unit() };
 
-                                                    let spliced_type_ladder = splice_ladders(
-                                                        last_args[i].clone().get_lnf_vec(),
-                                                        bot_args[i].clone().get_lnf_vec()
-                                                    );
-                                                    let spliced_type =
-                                                        if spliced_type_ladder.len() == 1 {
-                                                            spliced_type_ladder[0].clone()
-                                                        } else if spliced_type_ladder.len() > 1 {
-                                                            TypeTerm::Ladder(spliced_type_ladder)
-                                                        } else {
-                                                            TypeTerm::unit()
-                                                        };
-
-                                                    new_rung_params.push( spliced_type.param_normalize() );
-                                                }
-
-                                            } else {
-                                                new_rung_params.push(
-                                                    TypeTerm::Ladder(vec![
-                                                        last_args[0].clone(),
-                                                        bot_args[0].clone()
-                                                    ]).normalize()
-                                                );
-
-                                                for i in 1 .. bot_args.len() {
-                                                    if let Ok(_idx) = last_args[i].is_syntactic_subtype_of(&bot_args[i]) {
-                                                        let spliced_type_ladder = splice_ladders(
-                                                            last_args[i].clone().get_lnf_vec(),
-                                                            bot_args[i].clone().get_lnf_vec()
-                                                        );
-                                                        let spliced_type =
-                                                            if spliced_type_ladder.len() == 1 {
-                                                                spliced_type_ladder[0].clone()
-                                                            } else if spliced_type_ladder.len() > 1 {
-                                                                TypeTerm::Ladder(spliced_type_ladder)
-                                                            } else {
-                                                                TypeTerm::unit()
-                                                            };
-
-                                                        new_rung_params.push( spliced_type.param_normalize() );
-                                                    } else {
-                                                        new_rung_params.push( bot_args[i].clone() );
-                                                        require_break = true;
-                                                    }
-                                                }
-                                            }
-                                        }
-
-                                        if require_break {
-                                            new_rungs.push( TypeTerm::App(new_rung_params) );
+                                            Some(Box::new(
+                                                if sr1 == sr2 {
+                                                    sr1
+                                                } else if sr1 == TypeTerm::unit() {
+                                                    sr2
+                                                } else {
+                                                    TypeTerm::Ladder(vec![ sr1, sr2 ]).normalize()
+                                                }))
                                         } else {
-                                            rungs.pop();
-                                            rungs.push(TypeTerm::App(new_rung_params));
-                                        }
+                                            None
+                                        },
+                                    items:
+                                        items1.into_iter()
+                                            .zip(items2.into_iter())
+                                            .map(|(item1, item2)| {
+                                                if item1 == item2 {
+                                                    item1
+                                                } else {
+                                                    TypeTerm::Ladder(vec![ item1.clone(), item2 ])
+                                                }
+                                            })
+                                            .collect()
+                                };
+                        }
 
-                                    } else {
-                                        new_rungs.push( TypeTerm::App(bot_args) );
+                        (TypeTerm::Seq { seq_repr, items },
+                         TypeTerm::Spec( mut args )
+                        ) => {
+                            if args.len() == items.len()+1 {
+                                r2 = TypeTerm::Seq {
+                                    seq_repr: Some(Box::new(TypeTerm::Ladder(vec![
+                                        if let Some(seq_repr) = seq_repr {
+                                            *seq_repr.clone()
+                                        } else {
+                                            TypeTerm::unit()
+                                        },
+                                        args.remove(0)
+                                    ]).normalize())),
+
+                                    items: items.into_iter()
+                                        .zip(args.into_iter())
+                                        .map(|(i1, i2)| {
+                                            if i1 == i2 {
+                                                i1
+                                            } else {
+                                                TypeTerm::Ladder(vec![ i1, i2 ]).normalize()
+                                            }
+                                        })
+                                        .collect()
+                                };
+                            } else {
+                                new_rungs.push(r2);
+                                r2 = r1;
+                            }
+                        }
+
+                        (TypeTerm::Struct { struct_repr: struct_repr1, members: members1 },
+                         TypeTerm::Struct { struct_repr: struct_repr2, members: members2 }) => {
+
+                            let mut condensed_struct_repr = None;
+                            let mut condensed_members = Vec::new();
+                            let mut require_break = false;
+
+
+                            if let Some(struct_repr1) = struct_repr1 {
+                                if let Some(struct_repr2) = struct_repr2 {
+                                    condensed_struct_repr = Some(Box::new(TypeTerm::Ladder(
+                                        vec![
+                                            struct_repr1.as_ref().clone(),
+                                            struct_repr2.as_ref().clone()
+                                        ]
+                                    ).normalize()))
+                                } else {
+                                    condensed_struct_repr = Some(Box::new(struct_repr1.as_ref().clone()));
+                                }
+                            } else {
+                                condensed_struct_repr = struct_repr2.clone();
+                            }
+
+                            for StructMember{ symbol: symbol2, ty: ty2 } in members2.iter() {
+                                let mut found = false;
+                                for StructMember{ symbol: symbol1, ty: ty1 } in members1.iter() {
+                                    if symbol2 == symbol1 {
+                                        condensed_members.push(StructMember {
+                                            symbol: symbol1.clone(),
+                                            ty: TypeTerm::Ladder(vec![
+                                                ty1.clone(),
+                                                ty2.clone()
+                                            ]).normalize()
+                                        });
+
+                                        found = true;
+                                        break;
                                     }
                                 }
-                                (bottom, last_buf) => {
-                                    new_rungs.push( bottom );
+
+                                if ! found {
+                                    require_break = true;
                                 }
                             }
-                        } else {
-                            new_rungs.push( bottom );
+
+                            if require_break {
+                                new_rungs.push(r2);
+                                r2 = r1;
+                            } else {
+                                r2 = TypeTerm::Struct {
+                                    struct_repr: condensed_struct_repr,
+                                    members: condensed_members
+                                };
+                            }
+                        }
+
+                        (TypeTerm::Enum { enum_repr: enum_repr1, variants: variants1 },
+                         TypeTerm::Enum { enum_repr: enum_repr2, variants: variants2 }) => {
+                            let mut condensed_enum_repr = None;
+                            let mut condensed_variants = Vec::new();
+                            let mut require_break = false;
+
+                            if let Some(enum_repr1) = enum_repr1 {
+                                if let Some(enum_repr2) = enum_repr2 {
+                                    condensed_enum_repr = Some(Box::new(TypeTerm::Ladder(
+                                        vec![
+                                            enum_repr1.as_ref().clone(),
+                                            enum_repr2.as_ref().clone()
+                                        ]
+                                    ).normalize()))
+                                } else {
+                                    condensed_enum_repr = Some(Box::new(enum_repr1.as_ref().clone()));
+                                }
+                            } else {
+                                condensed_enum_repr = enum_repr2.clone();
+                            }
+
+                            for EnumVariant{ symbol: symbol2, ty: ty2 } in variants2.iter() {
+                                let mut found = false;
+                                for EnumVariant{ symbol: symbol1, ty: ty1 } in variants1.iter() {
+                                    if symbol2 == symbol1 {
+                                        condensed_variants.push(EnumVariant {
+                                            symbol: symbol1.clone(),
+                                            ty: TypeTerm::Ladder(vec![
+                                                ty1.clone(),
+                                                ty2.clone()
+                                            ]).normalize()
+                                        });
+
+                                        found = true;
+                                        break;
+                                    }
+                                }
+
+                                if ! found {
+                                    require_break = true;
+                                }
+                            }
+
+                            if require_break {
+                                new_rungs.push(r2);
+                                r2 = r1;
+                            } else {
+                                r2 = TypeTerm::Enum {
+                                    enum_repr: condensed_enum_repr,
+                                    variants: condensed_variants
+                                };
+                            }
+                        }
+
+                        (TypeTerm::Spec(args1), TypeTerm::Spec(args2)) => {
+                            if args1.len() == args2.len() {
+                                if let Ok((ψ,σ)) = constraint_system::subtype_unify(&args1[0], &args2[0]) {
+                                    let mut new_args = Vec::new();
+
+                                    for (a1, a2) in args1.into_iter().zip(args2.into_iter()) {
+                                        new_args.push(TypeTerm::Ladder(vec![ a1, a2 ]).normalize());
+                                    }
+
+                                    r2 = TypeTerm::Spec(new_args);
+                                    //new_rungs.push(r2.clone());
+                                } else {
+                                    new_rungs.push(r2);
+                                    r2 = r1;
+                                }
+                            } else {
+                                new_rungs.push(r2);
+                                r2 = r1;
+                            }
+                        }
+
+                        (TypeTerm::Univ(args1), TypeTerm::Univ(args2)) => {
+                            todo!();
+                        }
+
+                        (TypeTerm::Func(args1), TypeTerm::Func(args2)) => {
+                            todo!();
+                        }
+
+                        (TypeTerm::Morph(args1), TypeTerm::Morph(args2)) => {
+                            todo!();
+                        }
+
+                        (TypeTerm::Ladder(rr1), TypeTerm::Ladder(rr2)) => {
+                            if rr1.len() > 0 {
+                                let l = splice_ladders(rr1, rr2);
+                                r2 = TypeTerm::Ladder(l).normalize();
+                            }
+                        }
+
+                        (atomic1, TypeTerm::Ladder(mut rr2)) => {
+                            if !atomic1.is_empty() {
+                                if rr2.first() != Some(&atomic1) {
+                                    rr2.insert(0, atomic1);
+                                }
+                            }
+                            r2 = TypeTerm::Ladder(rr2).normalize();
+                        }
+
+
+                        (TypeTerm::Ladder(mut rr1), atomic2) => {
+                            if !atomic2.is_empty() {
+                                if rr1.last() != Some(&atomic2) {
+                                    rr1.push(atomic2);
+                                }
+                            }
+                            r2 = TypeTerm::Ladder(rr1).normalize();
+                        }
+
+
+                        (atomic1, atomic2) => {
+                            if atomic1.is_empty() {
+                            } else if atomic1 == atomic2 {
+                            } else if atomic2.is_empty() {
+                                r2 = atomic1;
+                            } else {
+                                new_rungs.push(atomic2);
+                                r2 = atomic1;
+                            }
                         }
                     }
+                }
 
+                if new_rungs.len() > 0 {
+                    new_rungs.push(r2);
                     new_rungs.reverse();
-
-                    if new_rungs.len() > 1 {
-                        TypeTerm::Ladder(new_rungs)
-                    } else if new_rungs.len() == 1 {
-                        new_rungs[0].clone()
-                    } else {
-                        TypeTerm::unit()
-                    }
+                    return TypeTerm::Ladder(new_rungs);
                 } else {
-                    TypeTerm::unit()
+                    return r2;
                 }
             }
 
-            TypeTerm::App(params) => {
-                TypeTerm::App(
+            TypeTerm::Spec(params) => {
+                TypeTerm::Spec(
                     params.into_iter()
-                        .map(|p| p.param_normalize())
+                        .map(|p| p.normalize())
                         .collect())
             }
 
+            TypeTerm::Seq { seq_repr, items } => TypeTerm::Seq {
+                seq_repr: if let Some(seq_repr) = seq_repr { Some(Box::new(seq_repr.normalize())) } else { None },
+                items: items.into_iter().map(|p| p.normalize()).collect()
+            },
+            TypeTerm::Struct { struct_repr, members } => TypeTerm::Struct {
+                struct_repr: if let Some(struct_repr) = struct_repr { Some(Box::new(struct_repr.normalize())) } else { None },
+                members: members.into_iter()
+                    .map(|StructMember{symbol, ty}|
+                        StructMember{ symbol, ty: ty.normalize() })
+                    .collect()
+            },
+            TypeTerm::Enum { enum_repr, variants } => TypeTerm::Enum {
+                enum_repr: if let Some(enum_repr) = enum_repr { Some(Box::new(enum_repr.normalize())) } else { None },
+                variants: variants.into_iter()
+                    .map(|EnumVariant{symbol, ty}|
+                        EnumVariant{ symbol, ty: ty.normalize() })
+                    .collect()
+            },
+
             atomic => atomic
         }
     }
diff --git a/src/pnf_sugared.rs b/src/pnf_sugared.rs
deleted file mode 100644
index 8fd3e71..0000000
--- a/src/pnf_sugared.rs
+++ /dev/null
@@ -1,334 +0,0 @@
-use crate::{sugar::SugaredTypeTerm, unification_sugared, SugaredEnumVariant, SugaredStructMember};
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-pub fn splice_ladders( mut upper: Vec< SugaredTypeTerm >, mut lower: Vec< SugaredTypeTerm >  ) -> Vec< SugaredTypeTerm > {
-    eprintln!("splice ladders {:?} <<<====>>>  {:?} ", upper, lower);
-    // check for overlap
-    for i in 0 .. upper.len() {
-        if upper[i] == lower[0] {
-            let mut result_ladder = Vec::<SugaredTypeTerm>::new();
-            result_ladder.append(&mut upper[0..i].iter().cloned().collect());
-            result_ladder.append(&mut lower);
-            return result_ladder;
-        }
-    }
-
-    // no overlap found, just concatenate ladders
-    upper.append(&mut lower);
-    upper
-}
-
-impl SugaredTypeTerm {
-    /// transmute type into Parameter-Normal-Form (PNF)
-    ///
-    /// Example:
-    /// ```ignore
-    /// <Seq <Digit 10>>~<Seq Char>
-    /// ⇒ <Seq <Digit 10>~Char>
-    /// ```
-    pub fn normalize(mut self) -> Self {
-        match self {
-            SugaredTypeTerm::Ladder(mut rungs) => {
-                if rungs.len() == 0 {
-                    return SugaredTypeTerm::unit();
-                } else if rungs.len() == 1 {
-                    return rungs.pop().unwrap().normalize();
-                }
-
-                let mut new_rungs = Vec::new();
-                let mut r2 = rungs.pop().unwrap().strip();
-                while let Some(r1) = rungs.pop() {
-                    let r1 = r1.strip();
-                    match (r1.clone(), r2.clone()) {
-                        (SugaredTypeTerm::Seq { seq_repr: seq_repr1, items: items1 },
-                         SugaredTypeTerm::Seq { seq_repr: seq_repr2, items: items2 })
-                        => {
-                            r2 = SugaredTypeTerm::Seq {
-                                    seq_repr:
-                                        if seq_repr1.is_some() || seq_repr2.is_some() {
-                                            let sr1 = if let Some(seq_repr1) = seq_repr1 { *seq_repr1.clone() }
-                                                        else { SugaredTypeTerm::unit() };
-                                            let sr2 = if let Some(seq_repr2) = seq_repr2 { *seq_repr2 }
-                                                        else { SugaredTypeTerm::unit() };
-
-                                            Some(Box::new(
-                                                if sr1 == sr2 {
-                                                    sr1
-                                                } else if sr1 == SugaredTypeTerm::unit() {
-                                                    sr2
-                                                } else {
-                                                    SugaredTypeTerm::Ladder(vec![ sr1, sr2 ]).normalize()
-                                                }))
-                                        } else {
-                                            None
-                                        },
-                                    items:
-                                        items1.into_iter()
-                                            .zip(items2.into_iter())
-                                            .map(|(item1, item2)| {
-                                                if item1 == item2 {
-                                                    item1
-                                                } else {
-                                                    SugaredTypeTerm::Ladder(vec![ item1.clone(), item2 ])
-                                                }
-                                            })
-                                            .collect()
-                                };
-                        }
-
-                        (SugaredTypeTerm::Seq { seq_repr, items },
-                            SugaredTypeTerm::Spec( mut args )
-                        ) => {
-                            if args.len() == items.len()+1 {
-                                r2 = SugaredTypeTerm::Seq {
-                                    seq_repr: Some(Box::new(SugaredTypeTerm::Ladder(vec![
-                                        if let Some(seq_repr) = seq_repr {
-                                            *seq_repr.clone()
-                                        } else {
-                                            SugaredTypeTerm::unit()
-                                        },
-                                        args.remove(0)
-                                    ]).normalize())),
-
-                                    items: items.into_iter()
-                                        .zip(args.into_iter())
-                                        .map(|(i1, i2)| {
-                                            if i1 == i2 {
-                                                i1
-                                            } else {
-                                                SugaredTypeTerm::Ladder(vec![ i1, i2 ]).normalize()
-                                            }
-                                        })
-                                        .collect()
-                                };
-                            } else {
-                                new_rungs.push(r2);
-                                r2 = r1;
-                            }
-                        }
-
-                        (SugaredTypeTerm::Struct { struct_repr: struct_repr1, members: members1 },
-                         SugaredTypeTerm::Struct { struct_repr: struct_repr2, members: members2 }) => {
-
-                            let mut condensed_struct_repr = None;
-                            let mut condensed_members = Vec::new();
-                            let mut require_break = false;
-
-
-                            if let Some(struct_repr1) = struct_repr1 {
-                                if let Some(struct_repr2) = struct_repr2 {
-                                    condensed_struct_repr = Some(Box::new(SugaredTypeTerm::Ladder(
-                                        vec![
-                                            struct_repr1.as_ref().clone(),
-                                            struct_repr2.as_ref().clone()
-                                        ]
-                                    ).normalize()))
-                                } else {
-                                    condensed_struct_repr = Some(Box::new(struct_repr1.as_ref().clone()));
-                                }
-                            } else {
-                                condensed_struct_repr = struct_repr2.clone();
-                            }
-
-                            for SugaredStructMember{ symbol: symbol2, ty: ty2 } in members2.iter() {
-                                let mut found = false;
-                                for SugaredStructMember{ symbol: symbol1, ty: ty1 } in members1.iter() {
-                                    if symbol2 == symbol1 {
-                                        condensed_members.push(SugaredStructMember {
-                                            symbol: symbol1.clone(),
-                                            ty: SugaredTypeTerm::Ladder(vec![
-                                                ty1.clone(),
-                                                ty2.clone()
-                                            ]).normalize()
-                                        });
-
-                                        found = true;
-                                        break;
-                                    }
-                                }
-
-                                if ! found {
-                                    require_break = true;
-                                }
-                            }
-
-                            if require_break {
-                                new_rungs.push(r2);
-                                r2 = r1;
-                            } else {
-                                r2 = SugaredTypeTerm::Struct {
-                                    struct_repr: condensed_struct_repr,
-                                    members: condensed_members
-                                };
-                            }
-                        }
-
-                        (SugaredTypeTerm::Enum { enum_repr: enum_repr1, variants: variants1 },
-                         SugaredTypeTerm::Enum { enum_repr: enum_repr2, variants: variants2 }) => {
-                            let mut condensed_enum_repr = None;
-                            let mut condensed_variants = Vec::new();
-                            let mut require_break = false;
-
-                            if let Some(enum_repr1) = enum_repr1 {
-                                if let Some(enum_repr2) = enum_repr2 {
-                                    condensed_enum_repr = Some(Box::new(SugaredTypeTerm::Ladder(
-                                        vec![
-                                            enum_repr1.as_ref().clone(),
-                                            enum_repr2.as_ref().clone()
-                                        ]
-                                    ).normalize()))
-                                } else {
-                                    condensed_enum_repr = Some(Box::new(enum_repr1.as_ref().clone()));
-                                }
-                            } else {
-                                condensed_enum_repr = enum_repr2.clone();
-                            }
-
-                            for SugaredEnumVariant{ symbol: symbol2, ty: ty2 } in variants2.iter() {
-                                let mut found = false;
-                                for SugaredEnumVariant{ symbol: symbol1, ty: ty1 } in variants1.iter() {
-                                    if symbol2 == symbol1 {
-                                        condensed_variants.push(SugaredEnumVariant {
-                                            symbol: symbol1.clone(),
-                                            ty: SugaredTypeTerm::Ladder(vec![
-                                                ty1.clone(),
-                                                ty2.clone()
-                                            ]).normalize()
-                                        });
-
-                                        found = true;
-                                        break;
-                                    }
-                                }
-
-                                if ! found {
-                                    require_break = true;
-                                }
-                            }
-
-                            if require_break {
-                                new_rungs.push(r2);
-                                r2 = r1;
-                            } else {
-                                r2 = SugaredTypeTerm::Enum {
-                                    enum_repr: condensed_enum_repr,
-                                    variants: condensed_variants
-                                };
-                            }
-                        }
-
-                        (SugaredTypeTerm::Spec(args1), SugaredTypeTerm::Spec(args2)) => {
-                            if args1.len() == args2.len() {
-                                if let Ok((ψ,σ)) = unification_sugared::subtype_unify(&args1[0], &args2[0]) {
-                                    let mut new_args = Vec::new();
-
-                                    for (a1, a2) in args1.into_iter().zip(args2.into_iter()) {
-                                        new_args.push(SugaredTypeTerm::Ladder(vec![ a1, a2 ]).normalize());
-                                    }
-
-                                    r2 = SugaredTypeTerm::Spec(new_args);
-                                    //new_rungs.push(r2.clone());
-                                } else {
-                                    new_rungs.push(r2);
-                                    r2 = r1;
-                                }
-                            } else {
-                                new_rungs.push(r2);
-                                r2 = r1;
-                            }
-                        }
-
-                        (SugaredTypeTerm::Univ(args1), SugaredTypeTerm::Univ(args2)) => {
-                            todo!();
-                        }
-
-                        (SugaredTypeTerm::Func(args1), SugaredTypeTerm::Func(args2)) => {
-                            todo!();
-                        }
-
-                        (SugaredTypeTerm::Morph(args1), SugaredTypeTerm::Morph(args2)) => {
-                            todo!();
-                        }
-
-                        (SugaredTypeTerm::Ladder(rr1), SugaredTypeTerm::Ladder(rr2)) => {
-                            if rr1.len() > 0 {
-                                let l = splice_ladders(rr1, rr2);
-                                r2 = SugaredTypeTerm::Ladder(l).normalize();
-                            }
-                        }
-
-                        (atomic1, SugaredTypeTerm::Ladder(mut rr2)) => {
-                            if !atomic1.is_empty() {
-                                if rr2.first() != Some(&atomic1) {
-                                    rr2.insert(0, atomic1);
-                                }
-                            }
-                            r2 = SugaredTypeTerm::Ladder(rr2).normalize();
-                        }
-
-
-                        (SugaredTypeTerm::Ladder(mut rr1), atomic2) => {
-                            if !atomic2.is_empty() {
-                                if rr1.last() != Some(&atomic2) {
-                                    rr1.push(atomic2);
-                                }
-                            }
-                            r2 = SugaredTypeTerm::Ladder(rr1).normalize();
-                        }
-
-
-                        (atomic1, atomic2) => {
-                            if atomic1.is_empty() {
-                            } else if atomic1 == atomic2 {
-                            } else if atomic2.is_empty() {
-                                r2 = atomic1;
-                            } else {
-                                new_rungs.push(atomic2);
-                                r2 = atomic1;
-                            }
-                        }
-                    }
-                }
-
-                if new_rungs.len() > 0 {
-                    new_rungs.push(r2);
-                    new_rungs.reverse();
-                    return SugaredTypeTerm::Ladder(new_rungs);
-                } else {
-                    return r2;
-                }
-            }
-
-            SugaredTypeTerm::Spec(params) => {
-                SugaredTypeTerm::Spec(
-                    params.into_iter()
-                        .map(|p| p.normalize())
-                        .collect())
-            }
-
-            SugaredTypeTerm::Seq { seq_repr, items } => SugaredTypeTerm::Seq {
-                seq_repr: if let Some(seq_repr) = seq_repr { Some(Box::new(seq_repr.normalize())) } else { None },
-                items: items.into_iter().map(|p| p.normalize()).collect()
-            },
-            SugaredTypeTerm::Struct { struct_repr, members } => SugaredTypeTerm::Struct {
-                struct_repr: if let Some(struct_repr) = struct_repr { Some(Box::new(struct_repr.normalize())) } else { None },
-                members: members.into_iter()
-                    .map(|SugaredStructMember{symbol, ty}|
-                        SugaredStructMember{ symbol, ty: ty.normalize() })
-                    .collect()
-            },
-            SugaredTypeTerm::Enum { enum_repr, variants } => SugaredTypeTerm::Enum{
-                enum_repr: if let Some(enum_repr) = enum_repr { Some(Box::new(enum_repr.normalize())) } else { None },
-                variants: variants.into_iter()
-                    .map(|SugaredEnumVariant{symbol, ty}|
-                        SugaredEnumVariant{ symbol, ty: ty.normalize() })
-                    .collect()
-            },
-
-            atomic => atomic
-        }
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/pretty.rs b/src/pretty.rs
index c3cc103..20fc5f8 100644
--- a/src/pretty.rs
+++ b/src/pretty.rs
@@ -1,25 +1,25 @@
 use {
-    crate::{dict::TypeID, sugar::SugaredTypeTerm, SugaredStructMember, SugaredEnumVariant, TypeDict},
+    crate::{dict::TypeID, term::TypeTerm, StructMember, EnumVariant, TypeDict},
     tiny_ansi::TinyAnsi
 };
 
 
-impl SugaredStructMember {
+impl StructMember {
     pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String {
         format!("{}: {}", self.symbol, self.ty.pretty(dict, indent+1))
     }
 }
-impl SugaredEnumVariant {
+impl EnumVariant {
     pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String {
         format!("{}: {}", self.symbol, self.ty.pretty(dict, indent+1))
     }
 }
 
-impl SugaredTypeTerm {
+impl TypeTerm {
     pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String {
         let indent_width = 4;
         match self {
-            SugaredTypeTerm::TypeID(id) => {
+            TypeTerm::TypeID(id) => {
                 match id {
                     TypeID::Var(varid) => {
                         format!("{}", dict.get_typename(id).unwrap_or("??".bright_red())).bright_magenta()
@@ -30,11 +30,11 @@ impl SugaredTypeTerm {
                 }
             },
 
-            SugaredTypeTerm::Num(n) => {
+            TypeTerm::Num(n) => {
                 format!("{}", n).green().bold()
             }
 
-            SugaredTypeTerm::Char(c) => {
+            TypeTerm::Char(c) => {
                 match c {
                     '\0' => format!("'\\0'"),
                     '\n' => format!("'\\n'"),
@@ -42,7 +42,7 @@ impl SugaredTypeTerm {
                 }
             }
 
-            SugaredTypeTerm::Univ(t) => {
+            TypeTerm::Univ(t) => {
                 format!("{} {} . {}",
                     "∀".yellow().bold(),
                     dict.get_varname(0).unwrap_or("??".into()).bright_blue(),
@@ -50,7 +50,7 @@ impl SugaredTypeTerm {
                 )
             }
 
-            SugaredTypeTerm::Spec(args) => {
+            TypeTerm::Spec(args) => {
                 let mut s = String::new();
                 s.push_str(&"<".yellow());
                 for i in 0..args.len() {
@@ -64,7 +64,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Struct{ struct_repr, members } => {
+            TypeTerm::Struct{ struct_repr, members } => {
                 let mut s = String::new();
                 s.push_str(&"{".yellow().bold());
 
@@ -89,7 +89,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Enum{ enum_repr, variants } => {
+            TypeTerm::Enum{ enum_repr, variants } => {
                 let mut s = String::new();
                 s.push_str(&"(".yellow().bold());
 
@@ -117,7 +117,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Seq{ seq_repr, items } => {
+            TypeTerm::Seq{ seq_repr, items } => {
                 let mut s = String::new();
                 s.push_str(&"[".yellow().bold());
 
@@ -136,7 +136,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Morph(args) => {
+            TypeTerm::Morph(args) => {
                 let mut s = String::new();
                 for arg in args {
                     s.push_str(&"  ~~morph~~>  ".bright_yellow());
@@ -145,7 +145,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Func(args) => {
+            TypeTerm::Func(args) => {
                 let mut s = String::new();
                 for i in 0..args.len() {
                     let arg = &args[i];
@@ -163,7 +163,7 @@ impl SugaredTypeTerm {
                 s
             }
 
-            SugaredTypeTerm::Ladder(rungs) => {
+            TypeTerm::Ladder(rungs) => {
                 let mut s = String::new();
                 for i in 0..rungs.len() {
                     let rung = &rungs[i];
diff --git a/src/steiner_tree.rs b/src/steiner_tree.rs
index 3df0aca..8783a97 100644
--- a/src/steiner_tree.rs
+++ b/src/steiner_tree.rs
@@ -1,10 +1,7 @@
 use {
     crate::{
-        morphism::{
-            Morphism, MorphismType
-        },
-        morphism_base::MorphismBase,
-        MorphismInstance, TypeID, TypeTerm
+        Morphism, MorphismType, MorphismBase,
+        TypeTerm, MorphismInstance, TypeID, DesugaredTypeTerm
     }, std::collections::HashMap
 };
 
@@ -63,7 +60,7 @@ impl SteinerTree {
 
     fn contains(&self, t: &TypeTerm) -> Option< HashMap<TypeID, TypeTerm> > {
         for e in self.edges.iter() {
-            if let Ok(σ) = crate::unify(&e.dst_type, t) {
+            if let Ok(σ) = crate::constraint_system::unify(&e.dst_type, t) {
                 return Some(σ)
             }
         }
@@ -230,7 +227,7 @@ impl SteinerTreeProblem {
 
             // extend the tree by one edge and add it to the queue
             for src_type in current_nodes {
-                for next_morph_inst in morphisms.enum_morphisms(&src_type) {
+                for next_morph_inst in morphisms.enum_morphisms_from(&src_type) {
                     //let dst_type = TypeTerm::Ladder(vec![dst_halo, dst_ty]).normalize();
                     let dst_type = next_morph_inst.get_type().dst_type;
 
diff --git a/src/substitution.rs b/src/substitution.rs
index 09935d0..738855d 100644
--- a/src/substitution.rs
+++ b/src/substitution.rs
@@ -1,25 +1,48 @@
 
+use std::ops::DerefMut;
 use crate::{
     TypeID,
-    TypeTerm
+    DesugaredTypeTerm
 };
+use crate::term::*;
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 pub trait Substitution {
     fn get(&self, t: &TypeID) -> Option< TypeTerm >;
-}
-
-impl<S: Fn(&TypeID)->Option<TypeTerm>> Substitution for S {
-    fn get(&self, t: &TypeID) -> Option< TypeTerm > {
-        (self)(t)
-    }
+    fn add(&mut self, tyid: TypeID, val: TypeTerm);
+    fn append(self, rhs: &Self) -> Self;
 }
 
 impl Substitution for std::collections::HashMap< TypeID, TypeTerm > {
     fn get(&self, t: &TypeID) -> Option< TypeTerm > {
         (self as &std::collections::HashMap< TypeID, TypeTerm >).get(t).cloned()
     }
+
+    fn add(&mut self, tyid: TypeID, val: TypeTerm) {
+        if let TypeID::Var(id) = tyid {
+            if !val.contains_var(id) {
+                self.insert(tyid, val.normalize());
+            } else {
+                eprintln!("substitution cannot contain loop");
+            }
+        }
+    }
+
+    fn append(self, rhs: &Self) -> Self {
+        let mut new_σ = std::collections::HashMap::new();
+        for (v, tt) in self.iter() {
+            let mut tt = tt.clone().normalize();
+            tt.apply_subst(rhs);
+            tt.apply_subst(&self);
+            new_σ.add(v.clone(), tt);
+        }
+        for (v, tt) in rhs.iter() {
+            new_σ.add(v.clone(), tt.clone().normalize());
+        }
+
+        new_σ
+    }
 }
 
 impl TypeTerm {
@@ -38,23 +61,50 @@ impl TypeTerm {
         σ: &impl Substitution
     ) -> &mut Self {
         match self {
+            TypeTerm::Num(_) => {},
+            TypeTerm::Char(_) => {},
+
             TypeTerm::TypeID(typid) => {
                 if let Some(t) = σ.get(typid) {
                     *self = t;
                 }
             }
-
-            TypeTerm::Ladder(rungs) => {
-                for r in rungs.iter_mut() {
-                    r.apply_subst(σ);
-                }
-            }
-            TypeTerm::App(args) => {
+            TypeTerm::Ladder(args) |
+            TypeTerm::Spec(args) |
+            TypeTerm::Func(args) |
+            TypeTerm::Morph(args)
+            => {
                 for r in args.iter_mut() {
                     r.apply_subst(σ);
                 }
             }
-            _ => {}
+
+            TypeTerm::Univ(t) => { t.apply_subst(σ); }
+
+            TypeTerm::Struct { struct_repr, members } => {
+                if let Some(struct_repr) = struct_repr.as_mut() {
+                    struct_repr.apply_subst(σ);
+                }
+                for StructMember{ symbol:_, ty } in members.iter_mut() {
+                    ty.apply_subst(σ);
+                }
+            },
+            TypeTerm::Enum { enum_repr, variants } => {
+                if let Some(enum_repr) = enum_repr.as_mut() {
+                    enum_repr.apply_subst(σ);
+                }
+                for EnumVariant{ symbol:_, ty } in variants.iter_mut() {
+                    ty.apply_subst(σ);
+                }
+            }
+            TypeTerm::Seq { seq_repr, items } => {
+                if let Some(seq_repr) = seq_repr {
+                    seq_repr.apply_subst(σ);
+                }
+                for ty in items.iter_mut() {
+                    ty.apply_subst(σ);
+                }
+            },
         }
 
         self
diff --git a/src/substitution_sugared.rs b/src/substitution_sugared.rs
deleted file mode 100644
index 1386e35..0000000
--- a/src/substitution_sugared.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-
-use std::ops::DerefMut;
-use crate::{
-    TypeID,
-    TypeTerm
-};
-use crate::sugar::*;
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-pub trait SugaredSubstitution {
-    fn get(&self, t: &TypeID) -> Option< SugaredTypeTerm >;
-    fn add(&mut self, tyid: TypeID, val: SugaredTypeTerm);
-    fn append(self, rhs: &Self) -> Self;
-}
-
-impl SugaredSubstitution for std::collections::HashMap< TypeID, SugaredTypeTerm > {
-    fn get(&self, t: &TypeID) -> Option< SugaredTypeTerm > {
-        (self as &std::collections::HashMap< TypeID, SugaredTypeTerm >).get(t).cloned()
-    }
-
-    fn add(&mut self, tyid: TypeID, val: SugaredTypeTerm) {
-        if let TypeID::Var(id) = tyid {
-            if !val.contains_var(id) {
-                self.insert(tyid, val);
-            } else {
-                eprintln!("substitution cannot contain loop");
-            }
-        }
-    }
-
-    fn append(self, rhs: &Self) -> Self {
-        let mut new_σ = std::collections::HashMap::new();
-        for (v, tt) in self.iter() {
-            let mut tt = tt.clone();
-            tt.apply_subst(rhs);
-            tt.apply_subst(&self);
-            new_σ.add(v.clone(), tt);
-        }
-        for (v, tt) in rhs.iter() {
-            new_σ.add(v.clone(), tt.clone());
-        }
-
-        new_σ
-    }
-}
-
-impl SugaredTypeTerm {
-    /// recursively apply substitution to all subterms,
-    /// which will replace all occurences of variables which map
-    /// some type-term in `subst`
-    pub fn apply_substitution(
-        &mut self,
-        σ: &impl SugaredSubstitution
-    ) -> &mut Self {
-        self.apply_subst(σ)
-    }
-
-    pub fn apply_subst(
-        &mut self,
-        σ: &impl SugaredSubstitution
-    ) -> &mut Self {
-        match self {
-            SugaredTypeTerm::Num(_) => {},
-            SugaredTypeTerm::Char(_) => {},
-
-            SugaredTypeTerm::TypeID(typid) => {
-                if let Some(t) = σ.get(typid) {
-                    *self = t;
-                }
-            }
-            SugaredTypeTerm::Ladder(args) |
-            SugaredTypeTerm::Spec(args) |
-            SugaredTypeTerm::Func(args) |
-            SugaredTypeTerm::Morph(args)
-            => {
-                for r in args.iter_mut() {
-                    r.apply_subst(σ);
-                }
-            }
-
-            SugaredTypeTerm::Univ(t) => { t.apply_subst(σ); }
-
-            SugaredTypeTerm::Struct { struct_repr, members } => {
-                if let Some(struct_repr) = struct_repr.as_mut() {
-                    struct_repr.apply_subst(σ);
-                }
-                for SugaredStructMember{ symbol:_, ty } in members.iter_mut() {
-                    ty.apply_subst(σ);
-                }
-            },
-            SugaredTypeTerm::Enum { enum_repr, variants } => {
-                if let Some(enum_repr) = enum_repr.as_mut() {
-                    enum_repr.apply_subst(σ);
-                }
-                for SugaredEnumVariant{ symbol:_, ty } in variants.iter_mut() {
-                    ty.apply_subst(σ);
-                }
-            }
-            SugaredTypeTerm::Seq { seq_repr, items } => {
-                if let Some(seq_repr) = seq_repr {
-                    seq_repr.apply_subst(σ);
-                }
-                for ty in items.iter_mut() {
-                    ty.apply_subst(σ);
-                }
-            },
-        }
-
-        self
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/subtype.rs b/src/subtype.rs
index 6843160..842f1e5 100644
--- a/src/subtype.rs
+++ b/src/subtype.rs
@@ -1,16 +1,16 @@
-use crate::term::TypeTerm;
+use crate::term::DesugaredTypeTerm;
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
-impl TypeTerm {
+impl DesugaredTypeTerm {
     // returns ladder-step of first match and provided representation-type
-    pub fn is_semantic_subtype_of(&self, expected_type: &TypeTerm) -> Option<(usize, TypeTerm)> {
+    pub fn is_semantic_subtype_of(&self, expected_type: &DesugaredTypeTerm) -> Option<(usize, DesugaredTypeTerm)> {
         let provided_lnf = self.clone().get_lnf_vec();
         let expected_lnf = expected_type.clone().get_lnf_vec();
 
         for i in 0..provided_lnf.len() {
             if provided_lnf[i] == expected_lnf[0] {
-                return Some((i, TypeTerm::Ladder(
+                return Some((i, DesugaredTypeTerm::Ladder(
                     provided_lnf[i..].into_iter().cloned().collect()
                 )))
             }
@@ -19,7 +19,7 @@ impl TypeTerm {
         None
     }
 
-    pub fn is_syntactic_subtype_of(&self, expected_type: &TypeTerm) -> Result<usize, (usize, usize)> {
+    pub fn is_syntactic_subtype_of(&self, expected_type: &DesugaredTypeTerm) -> Result<usize, (usize, usize)> {
         if let Some((first_match, provided_type)) = self.is_semantic_subtype_of( expected_type ) {
             let provided_lnf = provided_type.get_lnf_vec();
             let expected_lnf = expected_type.clone().get_lnf_vec();
@@ -39,11 +39,11 @@ impl TypeTerm {
 
     // supertype analogs
 
-    pub fn is_semantic_supertype_of(&self, t: &TypeTerm) -> Option<(usize, TypeTerm)> {
+    pub fn is_semantic_supertype_of(&self, t: &DesugaredTypeTerm) -> Option<(usize, DesugaredTypeTerm)> {
         t.is_semantic_subtype_of(self)
     }
 
-    pub fn is_syntactic_supertype_of(&self, t: &TypeTerm) -> Result<usize, (usize, usize)> {
+    pub fn is_syntactic_supertype_of(&self, t: &DesugaredTypeTerm) -> Result<usize, (usize, usize)> {
         t.is_syntactic_subtype_of(self)
     }
 }
@@ -52,10 +52,10 @@ impl TypeTerm {
 
 use crate::sugar::*;
 
-impl SugaredTypeTerm {
-    pub fn is_compatible(&self, supertype: SugaredTypeTerm) -> bool {
+impl TypeTerm {
+    pub fn is_compatible(&self, supertype: TypeTerm) -> bool {
         match (self, supertype) {
-            (SugaredTypeTerm::TypeID(idl), SugaredTypeTerm::TypeID(idr)) => {
+            (TypeTerm::TypeID(idl), TypeTerm::TypeID(idr)) => {
                 if *idl == idr {
                     true
                 } else {
@@ -64,7 +64,7 @@ impl SugaredTypeTerm {
             }
 
 
-            (SugaredTypeTerm::Ladder(l_rungs), SugaredTypeTerm::Ladder(r_rungs)) => {
+            (TypeTerm::Ladder(l_rungs), TypeTerm::Ladder(r_rungs)) => {
                 false
             }
 
diff --git a/src/sugar.rs b/src/sugar.rs
deleted file mode 100644
index de9c864..0000000
--- a/src/sugar.rs
+++ /dev/null
@@ -1,543 +0,0 @@
-use {
-    crate::{parser::ParseLadderType, subtype_unify, TypeDict, TypeID, TypeTerm}
-};
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct SugaredStructMember {
-    pub symbol: String,
-    pub ty: SugaredTypeTerm
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct SugaredEnumVariant {
-    pub symbol: String,
-    pub ty: SugaredTypeTerm
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum SugaredTypeTerm {
-    TypeID(TypeID),
-    Num(i64),
-    Char(char),
-    Univ(Box< SugaredTypeTerm >),
-    Spec(Vec< SugaredTypeTerm >),
-    Func(Vec< SugaredTypeTerm >),
-    Morph(Vec< SugaredTypeTerm >),
-    Ladder(Vec< SugaredTypeTerm >),
-    Struct{
-        struct_repr: Option< Box<SugaredTypeTerm> >,
-        members: Vec< SugaredStructMember >
-    },
-    Enum{
-        enum_repr: Option<Box< SugaredTypeTerm >>,
-        variants: Vec< SugaredEnumVariant >
-    },
-    Seq{
-        seq_repr: Option<Box< SugaredTypeTerm >>,
-        items: Vec< SugaredTypeTerm >
-    },
-
-    /*
-    Todo: Ref, RefMut
-    */
-}
-
-impl SugaredStructMember {
-    pub fn parse( dict: &mut impl TypeDict, ty: &TypeTerm ) -> Option<Self> {
-        match ty {
-            TypeTerm::App(args) => {
-                if args.len() != 2 {
-                    return None;
-                }
-/*
-                if args[0] != dict.parse("Struct.Field").expect("parse") {
-                    return None;
-                }
-*/
-                let symbol = match args[0] {
-                    TypeTerm::Char(c) => c.to_string(),
-                    TypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"),
-                    _ => {
-                        return None;
-                    }
-                };
-
-                let ty = args[1].clone().sugar(dict);
-
-                Some(SugaredStructMember { symbol, ty })
-            }
-            _ => {
-                None
-            }
-        }
-    }
-}
-
-impl SugaredEnumVariant {
-    pub fn parse( dict: &mut impl TypeDict, ty: &TypeTerm ) -> Option<Self> {
-        match ty {
-            TypeTerm::App(args) => {
-                if args.len() != 2 {
-                    return None;
-                }
-/*
-                if args[0] != dict.parse("Enum.Variant").expect("parse") {
-                    return None;
-                }
-*/
-                let symbol = match args[0] {
-                    TypeTerm::Char(c) => c.to_string(),
-                    TypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"),
-                    _ => {
-                        return None;
-                    }
-                };
-
-                let ty = args[1].clone().sugar(dict);
-
-                Some(SugaredEnumVariant { symbol, ty })
-            }
-            _ => {
-                None
-            }
-        }
-    }
-}
-
-impl TypeTerm {
-    pub fn sugar(self: TypeTerm, dict: &mut impl crate::TypeDict) -> SugaredTypeTerm {
-        dict.add_varname("StructRepr".into());
-        dict.add_varname("EnumRepr".into());
-        dict.add_varname("SeqRepr".into());
-
-        match self {
-            TypeTerm::TypeID(id) => SugaredTypeTerm::TypeID(id),
-            TypeTerm::Num(n) => SugaredTypeTerm::Num(n),
-            TypeTerm::Char(c) => SugaredTypeTerm::Char(c),
-            TypeTerm::App(args) => if let Some(first) = args.first() {
-                if first == &dict.parse("Func").unwrap() {
-                    SugaredTypeTerm::Func( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
-                }
-                else if first == &dict.parse("Morph").unwrap() {
-                    SugaredTypeTerm::Morph( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
-                }
-                else if first == &dict.parse("Struct").unwrap() {
-                    SugaredTypeTerm::Struct{
-                        struct_repr: None,
-                        members: args[1..].into_iter()
-                            .map(|t| SugaredStructMember::parse(dict, t).expect("cant parse field"))
-                            .collect()
-                    }
-                }
-                else if let Ok(σ) = crate::unify( first, &dict.parse("Struct ~ StructRepr").expect("") ) {
-                    SugaredTypeTerm::Struct{
-                        struct_repr: Some(Box::new(σ.get(&dict.get_typeid(&"StructRepr".into()).expect("")).unwrap().clone().sugar(dict))),
-                        members: args[1..].into_iter()
-                            .map(|t| SugaredStructMember::parse(dict, t).expect("cant parse field"))
-                            .collect()
-                    }
-                }
-                else if first == &dict.parse("Enum").unwrap() {
-                    SugaredTypeTerm::Enum{
-                        enum_repr: None,
-                        variants: args[1..].into_iter()
-                            .map(|t| SugaredEnumVariant::parse(dict, t).expect("cant parse variant"))
-                            .collect()
-                    }
-                }
-                else if let Ok(σ) = crate::unify( first, &dict.parse("Enum ~ EnumRepr").expect("") ) {
-                    SugaredTypeTerm::Enum{
-                        enum_repr: Some(Box::new(σ.get(&dict.get_typeid(&"EnumRepr".into()).expect("")).unwrap().clone().sugar(dict))),
-                        variants: args[1..].into_iter()
-                            .map(|t| SugaredEnumVariant::parse(dict, t).expect("cant parse variant"))
-                            .collect()
-                    }
-                }
-                else if first == &dict.parse("Seq").unwrap() {
-                    SugaredTypeTerm::Seq {
-                        seq_repr: None,
-                        items: args[1..].into_iter()
-                            .map(|t| t.clone().sugar(dict))
-                            .collect()
-                    }
-                }
-                else if let Ok(σ) = crate::unify( first, &dict.parse("Seq ~ SeqRepr").expect("") ) {
-                    SugaredTypeTerm::Seq {
-                        seq_repr: Some(Box::new(σ.get(&dict.get_typeid(&"SeqRepr".into()).expect("")).unwrap().clone().sugar(dict))),
-                        items: args[1..].into_iter()
-                            .map(|t| t.clone().sugar(dict))
-                            .collect()
-                    }
-                }
-                else if first == &dict.parse("Spec").unwrap() {
-                    SugaredTypeTerm::Spec( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
-                }
-                else if first == &dict.parse("Univ").unwrap() {
-                    SugaredTypeTerm::Univ(Box::new(
-                        SugaredTypeTerm::Spec(
-                            args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect()
-                        )
-                    ))
-                }
-                else {
-                    SugaredTypeTerm::Spec(args.into_iter().map(|t| t.sugar(dict)).collect())
-                }
-            } else {
-                SugaredTypeTerm::Spec(args.into_iter().map(|t| t.sugar(dict)).collect())
-            },
-            TypeTerm::Ladder(rungs) =>
-               SugaredTypeTerm::Ladder(rungs.into_iter().map(|t| t.sugar(dict)).collect())
-        }
-    }
-}
-
-
-impl SugaredStructMember {
-    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm {
-        TypeTerm::App(vec![
-            //dict.parse("Struct.Field").expect("parse"),
-            dict.parse(&self.symbol).expect("parse"),
-            self.ty.desugar(dict)
-        ])
-    }
-}
-
-impl SugaredEnumVariant {
-    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm {
-        TypeTerm::App(vec![
-            //dict.parse("Enum.Variant").expect("parse"),
-            dict.parse(&self.symbol).expect("parse"),
-            self.ty.desugar(dict)
-        ])
-    }
-}
-
-impl SugaredTypeTerm {
-    pub fn unit() -> Self {
-        SugaredTypeTerm::Ladder(vec![])
-    }
-
-    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm {
-        match self {
-            SugaredTypeTerm::TypeID(id) => TypeTerm::TypeID(id),
-            SugaredTypeTerm::Num(n) => TypeTerm::Num(n),
-            SugaredTypeTerm::Char(c) => TypeTerm::Char(c),
-            SugaredTypeTerm::Univ(t) => t.desugar(dict),
-            SugaredTypeTerm::Spec(ts) => TypeTerm::App(ts.into_iter().map(|t| t.desugar(dict)).collect()),
-            SugaredTypeTerm::Ladder(ts) => TypeTerm::Ladder(ts.into_iter().map(|t|t.desugar(dict)).collect()),
-            SugaredTypeTerm::Func(ts) => TypeTerm::App(
-                std::iter::once( dict.parse("Func").unwrap() ).chain(
-                    ts.into_iter().map(|t| t.desugar(dict))
-                ).collect()),
-            SugaredTypeTerm::Morph(ts) => TypeTerm::App(
-                std::iter::once( dict.parse("Morph").unwrap() ).chain(
-                    ts.into_iter().map(|t| t.desugar(dict))
-                ).collect()),
-            SugaredTypeTerm::Struct{ struct_repr, members } => TypeTerm::App(
-                std::iter::once(
-                    if let Some(sr) = struct_repr {
-                        TypeTerm::Ladder(vec![
-                            dict.parse("Struct").unwrap(),
-                            sr.desugar(dict)
-                        ])
-                    } else {
-                        dict.parse("Struct").unwrap()
-                    }
-                ).chain(
-                    members.into_iter().map(|t| t.desugar(dict))
-                ).collect()),
-            SugaredTypeTerm::Enum{ enum_repr, variants } => TypeTerm::App(
-                std::iter::once(
-                    if let Some(sr) = enum_repr {
-                        TypeTerm::Ladder(vec![
-                            dict.parse("Enum").unwrap(),
-                            sr.desugar(dict)
-                        ])
-                    } else {
-                        dict.parse("Enum").unwrap()
-                    }
-                ).chain(
-                    variants.into_iter().map(|t| t.desugar(dict))
-                ).collect()),
-            SugaredTypeTerm::Seq{ seq_repr, items } => TypeTerm::App(
-                std::iter::once(
-                    if let Some(sr) = seq_repr {
-                        TypeTerm::Ladder(vec![
-                            dict.parse("Seq").unwrap(),
-                            sr.desugar(dict)
-                        ])
-                    } else {
-                        dict.parse("Seq").unwrap()
-                    }
-                ).chain(
-                    items.into_iter().map(|t| t.desugar(dict))
-                ).collect()),
-        }
-    }
-
-    pub fn contains_var(&self, var_id: u64) -> bool {
-        match self {
-            SugaredTypeTerm::TypeID(TypeID::Var(v)) => (&var_id == v),
-            SugaredTypeTerm::Spec(args) |
-            SugaredTypeTerm::Func(args) |
-            SugaredTypeTerm::Morph(args) |
-            SugaredTypeTerm::Ladder(args) => {
-                for a in args.iter() {
-                    if a.contains_var(var_id) {
-                        return true;
-                    }
-                }
-                false
-            }
-            SugaredTypeTerm::Univ(t) => {
-                t.contains_var(var_id)
-            }
-            SugaredTypeTerm::Struct { struct_repr, members } => {
-                if let Some(struct_repr) =  struct_repr {
-                    if struct_repr.contains_var(var_id) {
-                        return true;
-                    }
-                }
-
-                for SugaredStructMember{ symbol, ty } in members {
-                    if ty.contains_var(var_id) {
-                        return true;
-                    }
-                }
-                false
-            }
-            SugaredTypeTerm::Enum { enum_repr, variants } => {
-                if let Some(enum_repr) =  enum_repr {
-                    if enum_repr.contains_var(var_id) {
-                        return true;
-                    }
-                }
-
-                for SugaredEnumVariant{ symbol, ty } in variants {
-                    if ty.contains_var(var_id) {
-                        return true;
-                    }
-                }
-                false
-            }
-            SugaredTypeTerm::Seq { seq_repr, items } => {
-                if let Some(seq_repr) =  seq_repr {
-                    if seq_repr.contains_var(var_id) {
-                        return true;
-                    }
-                }
-
-                for ty in items {
-                    if ty.contains_var(var_id) {
-                        return true;
-                    }
-                }
-                false
-            }
-
-            SugaredTypeTerm::Num(_) |
-            SugaredTypeTerm::Char(_) |
-            SugaredTypeTerm::TypeID(TypeID::Fun(_)) => false
-        }
-    }
-
-    pub fn strip(self) -> SugaredTypeTerm {
-        if self.is_empty() {
-            return SugaredTypeTerm::unit();
-        }
-
-        match self {
-            SugaredTypeTerm::Ladder(rungs) => {
-                let mut rungs :Vec<_> = rungs.into_iter()
-                    .filter_map(|mut r| {
-                        r = r.strip();
-                        if r != SugaredTypeTerm::unit() {
-                            Some(match r {
-                                SugaredTypeTerm::Ladder(r) => r,
-                                a => vec![ a ]
-                            })
-                        }
-                        else { None }
-                    })
-                .flatten()
-                .collect();
-
-                if rungs.len() == 1 {
-                    rungs.pop().unwrap()
-                } else {
-                    SugaredTypeTerm::Ladder(rungs)
-                }
-            },
-            SugaredTypeTerm::Spec(args) => {
-                let mut args :Vec<_> = args.into_iter().map(|arg| arg.strip()).collect();
-                if args.len() == 0 {
-                    SugaredTypeTerm::unit()
-                } else if args.len() == 1 {
-                    args.pop().unwrap()
-                } else {
-                    SugaredTypeTerm::Spec(args)
-                }
-            }
-            SugaredTypeTerm::Seq{ mut seq_repr, mut items } => {
-                if let Some(seq_repr) = seq_repr.as_mut() {
-                    *seq_repr = Box::new(seq_repr.clone().strip());
-                }
-                for i in items.iter_mut() {
-                    *i = i.clone().strip();
-                }
-
-                SugaredTypeTerm::Seq { seq_repr, items }
-            }
-            atom => atom
-        }
-    }
-
-
-    pub fn get_interface_type(&self) -> SugaredTypeTerm {
-        match self {
-            SugaredTypeTerm::Ladder(rungs) => {
-                if let Some(top) = rungs.first() {
-                    top.get_interface_type()
-                } else {
-                    SugaredTypeTerm::unit()
-                }
-            }
-            SugaredTypeTerm::Spec(args)
-                => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()),
-
-            SugaredTypeTerm::Func(args)
-                => SugaredTypeTerm::Func(args.iter().map(|a| a.get_interface_type()).collect()),
-
-            SugaredTypeTerm::Morph(args)
-                => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()),
-
-            SugaredTypeTerm::Univ(t)
-                => SugaredTypeTerm::Univ(Box::new(t.get_interface_type())),
-
-            SugaredTypeTerm::Seq { seq_repr, items } => {
-                SugaredTypeTerm::Seq {
-                    seq_repr: if let Some(sr) = seq_repr {
-                        Some(Box::new(sr.clone().get_interface_type()))
-                    } else { None },
-                    items: items.iter().map(|t| t.get_interface_type()).collect()
-                }
-            }
-            SugaredTypeTerm::Struct { struct_repr, members } => {
-                SugaredTypeTerm::Struct {
-                    struct_repr: if let Some(sr) = struct_repr {
-                        Some(Box::new(sr.clone().get_interface_type()))
-                    } else { None },
-                    members: members.iter()
-                        .map(|SugaredStructMember{symbol,ty}|
-                            SugaredStructMember {symbol:symbol.clone(), ty:ty.get_interface_type() })
-                        .collect()
-                }
-            }
-            SugaredTypeTerm::Enum { enum_repr, variants } => {
-                SugaredTypeTerm::Enum {
-                    enum_repr: if let Some(sr) = enum_repr {
-                        Some(Box::new(sr.clone().get_interface_type()))
-                    } else { None },
-                    variants: variants.iter()
-                        .map(|SugaredEnumVariant{symbol,ty}|
-                            SugaredEnumVariant{ symbol:symbol.clone(), ty:ty.get_interface_type() })
-                        .collect()
-                }
-            }
-
-            SugaredTypeTerm::TypeID(tyid) => SugaredTypeTerm::TypeID(tyid.clone()),
-            SugaredTypeTerm::Num(n) => SugaredTypeTerm::Num(*n),
-            SugaredTypeTerm::Char(c) => SugaredTypeTerm::Char(*c)
-        }
-    }
-
-    pub fn get_floor_type(&self) -> (SugaredTypeTerm, SugaredTypeTerm) {
-        match self.clone() {
-            SugaredTypeTerm::Ladder(mut rungs) => {
-                if let Some(bot) = rungs.pop() {
-                    let (bot_ψ, bot_floor) = bot.get_floor_type();
-                    rungs.push(bot_ψ);
-                    (SugaredTypeTerm::Ladder(rungs).strip(), bot_floor.strip())
-                } else {
-                    (SugaredTypeTerm::unit(), SugaredTypeTerm::unit())
-                }
-            }
-            /*
-            SugaredTypeTerm::Spec(args)
-                => (SugaredTypeTerm::SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()),
-
-            SugaredTypeTerm::Func(args)
-                => SugaredTypeTerm::Func(args.iter().map(|a| a.get_floor_type()).collect()),
-
-            SugaredTypeTerm::Morph(args)
-                => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()),
-
-            SugaredTypeTerm::Univ(t)
-                => SugaredTypeTerm::Univ(Box::new(t.get_floor_type())),
-
-            SugaredTypeTerm::Seq { seq_repr, items } => {
-                SugaredTypeTerm::Seq {
-                    seq_repr: if let Some(sr) = seq_repr {
-                        Some(Box::new(sr.clone().get_floor_type()))
-                    } else { None },
-                    items: items.iter().map(|t| t.get_floor_type()).collect()
-                }
-            }
-            SugaredTypeTerm::Struct { struct_repr, members } => {
-                SugaredTypeTerm::Struct {
-                    struct_repr: if let Some(sr) = struct_repr {
-                        Some(Box::new(sr.clone().get_floor_type()))
-                    } else { None },
-                    members: members.iter()
-                        .map(|SugaredStructMember{symbol,ty}|
-                            SugaredStructMember {symbol:symbol.clone(), ty:ty.get_floor_type() })
-                        .collect()
-                }
-            }
-            SugaredTypeTerm::Enum { enum_repr, variants } => {
-                SugaredTypeTerm::Enum {
-                    enum_repr: if let Some(sr) = enum_repr {
-                        Some(Box::new(sr.clone().get_floor_type()))
-                    } else { None },
-                    variants: variants.iter()
-                        .map(|SugaredEnumVariant{symbol,ty}|
-                            SugaredEnumVariant{ symbol:symbol.clone(), ty:ty.get_floor_type() })
-                        .collect()
-                }
-            }
-
-            SugaredTypeTerm::TypeID(tyid) => SugaredTypeTerm::TypeID(tyid.clone()),
-            SugaredTypeTerm::Num(n) => SugaredTypeTerm::Num(*n),
-            SugaredTypeTerm::Char(c) => SugaredTypeTerm::Char(*c)
-            */
-
-            other => (SugaredTypeTerm::unit(), other.clone().strip())
-        }
-    }
-
-    pub fn is_empty(&self) -> bool {
-        match self {
-            SugaredTypeTerm::TypeID(_) => false,
-            SugaredTypeTerm::Num(_) => false,
-            SugaredTypeTerm::Char(_) => false,
-            SugaredTypeTerm::Univ(t) => t.is_empty(),
-            SugaredTypeTerm::Spec(ts) |
-            SugaredTypeTerm::Ladder(ts) |
-            SugaredTypeTerm::Func(ts) |
-            SugaredTypeTerm::Morph(ts) => {
-                ts.iter().fold(true, |s,t| s && t.is_empty() )
-            }
-            SugaredTypeTerm::Seq{ seq_repr, items } => {
-                items.iter().fold(true, |s,t| s && t.is_empty() )
-            }
-            SugaredTypeTerm::Struct{ struct_repr, members } => {
-                members.iter()
-                    .fold(true, |s,member_decl| s && member_decl.ty.is_empty() )
-            }
-            SugaredTypeTerm::Enum{ enum_repr, variants } => {
-                variants.iter()
-                    .fold(true, |s,variant_decl| s && variant_decl.ty.is_empty() )
-            }
-        }
-    }
-}
diff --git a/src/term.rs b/src/term.rs
index 1cbd73a..f6dbf0f 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -1,85 +1,328 @@
-use crate::TypeID;
+use {
+    crate::{parser::ParseLadderType, subtype_unify, DesugaredTypeTerm, TypeDict, TypeID}
+};
 
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub enum TypeTerm {
-
-    /* Atomic Terms */
-
-    // Base types from dictionary
-    TypeID(TypeID),
-
-    // Literals
-    Num(i64),
-    Char(char),
-
-    /* Complex Terms */
-
-    // Type Parameters
-    // avoid currying to save space & indirection
-    App(Vec< TypeTerm >),
-
-    // Type Ladders
-    Ladder(Vec< TypeTerm >),
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct StructMember {
+    pub symbol: String,
+    pub ty: TypeTerm
 }
 
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct EnumVariant {
+    pub symbol: String,
+    pub ty: TypeTerm
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum TypeTerm {
+    TypeID(TypeID),
+    Num(i64),
+    Char(char),
+    Univ(Box< TypeTerm >),
+    Spec(Vec< TypeTerm >),
+    Func(Vec< TypeTerm >),
+    Morph(Vec< TypeTerm >),
+    Ladder(Vec< TypeTerm >),
+    Struct{
+        struct_repr: Option< Box<TypeTerm> >,
+        members: Vec< StructMember >
+    },
+    Enum{
+        enum_repr: Option<Box< TypeTerm >>,
+        variants: Vec< EnumVariant >
+    },
+    Seq{
+        seq_repr: Option<Box< TypeTerm >>,
+        items: Vec< TypeTerm >
+    },
+
+    /*
+    Todo: Ref, RefMut
+    */
+}
+
+impl StructMember {
+    pub fn parse( dict: &mut impl TypeDict, ty: &DesugaredTypeTerm ) -> Option<Self> {
+        match ty {
+            DesugaredTypeTerm::App(args) => {
+                if args.len() != 2 {
+                    return None;
+                }
+/*
+                if args[0] != dict.parse("Struct.Field").expect("parse") {
+                    return None;
+                }
+*/
+                let symbol = match args[0] {
+                    DesugaredTypeTerm::Char(c) => c.to_string(),
+                    DesugaredTypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"),
+                    _ => {
+                        return None;
+                    }
+                };
+
+                let ty = args[1].clone().sugar(dict);
+
+                Some(StructMember { symbol, ty })
+            }
+            _ => {
+                None
+            }
+        }
+    }
+}
+
+impl EnumVariant {
+    pub fn parse( dict: &mut impl TypeDict, ty: &DesugaredTypeTerm ) -> Option<Self> {
+        match ty {
+            DesugaredTypeTerm::App(args) => {
+                if args.len() != 2 {
+                    return None;
+                }
+/*
+                if args[0] != dict.parse("Enum.Variant").expect("parse") {
+                    return None;
+                }
+*/
+                let symbol = match args[0] {
+                    DesugaredTypeTerm::Char(c) => c.to_string(),
+                    DesugaredTypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"),
+                    _ => {
+                        return None;
+                    }
+                };
+
+                let ty = args[1].clone().sugar(dict);
+
+                Some(EnumVariant { symbol, ty })
+            }
+            _ => {
+                None
+            }
+        }
+    }
+}
+
+impl DesugaredTypeTerm {
+    pub fn sugar(self: DesugaredTypeTerm, dict: &mut impl crate::TypeDict) -> TypeTerm {
+        dict.add_varname("StructRepr".into());
+        dict.add_varname("EnumRepr".into());
+        dict.add_varname("SeqRepr".into());
+
+        match self {
+            DesugaredTypeTerm::TypeID(id) => TypeTerm::TypeID(id),
+            DesugaredTypeTerm::Num(n) => TypeTerm::Num(n),
+            DesugaredTypeTerm::Char(c) => TypeTerm::Char(c),
+            DesugaredTypeTerm::App(args) => if let Some(first) = args.first() {
+                if first == &dict.parse_desugared("Func").unwrap() {
+                    TypeTerm::Func( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
+                }
+                else if first == &dict.parse_desugared("Morph").unwrap() {
+                    TypeTerm::Morph( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
+                }
+                else if first == &dict.parse_desugared("Seq").unwrap() {
+                    TypeTerm::Seq{
+                        seq_repr: None,
+                        items: args[1..].into_iter()
+                            .map(|t| t.clone().sugar(dict))
+                            .collect()
+                    }
+                }
+                else if first == &dict.parse_desugared("Struct").unwrap() {
+                    TypeTerm::Struct{
+                        struct_repr: None,
+                        members: args[1..].into_iter()
+                            .map(|t| StructMember::parse(dict, t).expect("cant parse field"))
+                            .collect()
+                    }
+                }
+                else if first == &dict.parse_desugared("Enum").unwrap() {
+                    TypeTerm::Enum{
+                        enum_repr: None,
+                        variants: args[1..].into_iter()
+                            .map(|t| EnumVariant::parse(dict, t).expect("cant parse variant"))
+                            .collect()
+                    }
+                }
+                else if let DesugaredTypeTerm::Ladder(mut rungs) = first.clone() {
+                    if rungs.len() > 0 {
+                        match rungs.remove(0) {
+                            DesugaredTypeTerm::TypeID(tyid) => {
+                                if tyid == dict.get_typeid(&"Seq".into()).expect("") {
+                                    TypeTerm::Seq {
+                                        seq_repr:
+                                            if rungs.len() > 0 {
+                                                Some(Box::new(
+                                                    TypeTerm::Ladder(rungs.into_iter()
+                                                        .map(|r| r.clone().sugar(dict))
+                                                        .collect()
+                                                    ).normalize()
+                                                ))
+                                            } else {
+                                                None
+                                            },
+                                        items: args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect()
+                                    }
+                                } else if tyid == dict.get_typeid(&"Struct".into()).expect("") {
+                                    TypeTerm::Struct {
+                                        struct_repr:
+                                            if rungs.len() > 0 {
+                                                Some(Box::new(
+                                                    TypeTerm::Ladder(rungs.into_iter()
+                                                        .map(|r| r.clone().sugar(dict))
+                                                        .collect()
+                                                    ).normalize()
+                                                ))
+                                            } else {
+                                                None
+                                            },
+                                        members: args[1..].into_iter()
+                                            .map(|t| StructMember::parse(dict, t).expect("cant parse field"))
+                                            .collect()
+                                    }
+                                } else if tyid == dict.get_typeid(&"Enum".into()).expect("") {
+                                    TypeTerm::Enum {
+                                        enum_repr:
+                                            if rungs.len() > 0 {
+                                                Some(Box::new(
+                                                    TypeTerm::Ladder(rungs.into_iter()
+                                                        .map(|r| r.clone().sugar(dict))
+                                                        .collect()
+                                                    ).normalize()
+                                                ))
+                                            } else {
+                                                None
+                                            },
+                                        variants: args[1..].into_iter()
+                                            .map(|t| EnumVariant::parse(dict, t).expect("cant parse field"))
+                                            .collect()
+                                    }
+                                } else {
+                                    TypeTerm::Spec(args.into_iter().map(|t| t.sugar(dict)).collect())
+                                }
+                            }
+                            _ => {
+                                unreachable!();
+                            }
+                        }
+                    } else {
+                        unreachable!();
+                    }
+                }
+
+                else if first == &dict.parse_desugared("Spec").unwrap() {
+                    TypeTerm::Spec( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() )
+                }
+                else if first == &dict.parse_desugared("Univ").unwrap() {
+                    TypeTerm::Univ(Box::new(
+                        TypeTerm::Spec(
+                            args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect()
+                        )
+                    ))
+                }
+                else {
+                    TypeTerm::Spec(args.into_iter().map(|t| t.sugar(dict)).collect())
+                }
+            } else {
+                TypeTerm::Spec(args.into_iter().map(|t| t.sugar(dict)).collect())
+            },
+            DesugaredTypeTerm::Ladder(rungs) =>
+               TypeTerm::Ladder(rungs.into_iter().map(|t| t.sugar(dict)).collect())
+        }
+    }
+}
+
+
+impl StructMember {
+    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> DesugaredTypeTerm {
+        DesugaredTypeTerm::App(vec![
+            //dict.parse("Struct.Field").expect("parse"),
+            dict.parse_desugared(&self.symbol).expect("parse"),
+            self.ty.desugar(dict)
+        ])
+    }
+}
+
+impl EnumVariant {
+    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> DesugaredTypeTerm {
+        DesugaredTypeTerm::App(vec![
+            //dict.parse("Enum.Variant").expect("parse"),
+            dict.parse_desugared(&self.symbol).expect("parse"),
+            self.ty.desugar(dict)
+        ])
+    }
+}
 
 impl TypeTerm {
     pub fn unit() -> Self {
         TypeTerm::Ladder(vec![])
     }
 
-    pub fn new(id: TypeID) -> Self {
-        TypeTerm::TypeID(id)
-    }
-
-    pub fn arg(&mut self, t: impl Into<TypeTerm>) -> &mut Self {
+    pub fn desugar(self, dict: &mut impl crate::TypeDict) -> DesugaredTypeTerm {
         match self {
-            TypeTerm::App(args) => {
-                args.push(t.into());
-            }
-
-            _ => {
-                *self = TypeTerm::App(vec![
-                    self.clone(),
-                    t.into()
-                ])
-            }
+            TypeTerm::TypeID(id) => DesugaredTypeTerm::TypeID(id),
+            TypeTerm::Num(n) => DesugaredTypeTerm::Num(n),
+            TypeTerm::Char(c) => DesugaredTypeTerm::Char(c),
+            TypeTerm::Univ(t) => t.desugar(dict),
+            TypeTerm::Spec(ts) => DesugaredTypeTerm::App(ts.into_iter().map(|t| t.desugar(dict)).collect()),
+            TypeTerm::Ladder(ts) => DesugaredTypeTerm::Ladder(ts.into_iter().map(|t|t.desugar(dict)).collect()),
+            TypeTerm::Func(ts) => DesugaredTypeTerm::App(
+                std::iter::once( dict.parse_desugared("Func").unwrap() ).chain(
+                    ts.into_iter().map(|t| t.desugar(dict))
+                ).collect()),
+            TypeTerm::Morph(ts) => DesugaredTypeTerm::App(
+                std::iter::once( dict.parse_desugared("Morph").unwrap() ).chain(
+                    ts.into_iter().map(|t| t.desugar(dict))
+                ).collect()),
+            TypeTerm::Struct{ struct_repr, members } => DesugaredTypeTerm::App(
+                std::iter::once(
+                    if let Some(sr) = struct_repr {
+                        DesugaredTypeTerm::Ladder(vec![
+                            dict.parse_desugared("Struct").unwrap(),
+                            sr.desugar(dict)
+                        ])
+                    } else {
+                        dict.parse_desugared("Struct").unwrap()
+                    }
+                ).chain(
+                    members.into_iter().map(|t| t.desugar(dict))
+                ).collect()),
+            TypeTerm::Enum{ enum_repr, variants } => DesugaredTypeTerm::App(
+                std::iter::once(
+                    if let Some(sr) = enum_repr {
+                        DesugaredTypeTerm::Ladder(vec![
+                            dict.parse_desugared("Enum").unwrap(),
+                            sr.desugar(dict)
+                        ])
+                    } else {
+                        dict.parse_desugared("Enum").unwrap()
+                    }
+                ).chain(
+                    variants.into_iter().map(|t| t.desugar(dict))
+                ).collect()),
+            TypeTerm::Seq{ seq_repr, items } => DesugaredTypeTerm::App(
+                std::iter::once(
+                    if let Some(sr) = seq_repr {
+                        DesugaredTypeTerm::Ladder(vec![
+                            dict.parse_desugared("Seq").unwrap(),
+                            sr.desugar(dict)
+                        ])
+                    } else {
+                        dict.parse_desugared("Seq").unwrap()
+                    }
+                ).chain(
+                    items.into_iter().map(|t| t.desugar(dict))
+                ).collect()),
         }
-        self
-    }
-
-    pub fn repr_as(&mut self, t: impl Into<TypeTerm>) -> &mut Self {
-        match self {
-            TypeTerm::Ladder(rungs) => {
-                rungs.push(t.into());
-            }
-
-            _ => {
-                *self = TypeTerm::Ladder(vec![
-                    self.clone(),
-                    t.into()
-                ])
-            }
-        }
-
-        self
-    }
-
-    pub fn num_arg(&mut self, v: i64) -> &mut Self {
-        self.arg(TypeTerm::Num(v))
-    }
-
-    pub fn char_arg(&mut self, c: char) -> &mut Self {
-        self.arg(TypeTerm::Char(c))
     }
 
     pub fn contains_var(&self, var_id: u64) -> bool {
         match self {
             TypeTerm::TypeID(TypeID::Var(v)) => (&var_id == v),
-            TypeTerm::App(args) |
+            TypeTerm::Spec(args) |
+            TypeTerm::Func(args) |
+            TypeTerm::Morph(args) |
             TypeTerm::Ladder(args) => {
                 for a in args.iter() {
                     if a.contains_var(var_id) {
@@ -88,15 +331,63 @@ impl TypeTerm {
                 }
                 false
             }
-            _ => false
+            TypeTerm::Univ(t) => {
+                t.contains_var(var_id)
+            }
+            TypeTerm::Struct { struct_repr, members } => {
+                if let Some(struct_repr) =  struct_repr {
+                    if struct_repr.contains_var(var_id) {
+                        return true;
+                    }
+                }
+
+                for StructMember{ symbol, ty } in members {
+                    if ty.contains_var(var_id) {
+                        return true;
+                    }
+                }
+                false
+            }
+            TypeTerm::Enum { enum_repr, variants } => {
+                if let Some(enum_repr) =  enum_repr {
+                    if enum_repr.contains_var(var_id) {
+                        return true;
+                    }
+                }
+
+                for EnumVariant{ symbol, ty } in variants {
+                    if ty.contains_var(var_id) {
+                        return true;
+                    }
+                }
+                false
+            }
+            TypeTerm::Seq { seq_repr, items } => {
+                if let Some(seq_repr) =  seq_repr {
+                    if seq_repr.contains_var(var_id) {
+                        return true;
+                    }
+                }
+
+                for ty in items {
+                    if ty.contains_var(var_id) {
+                        return true;
+                    }
+                }
+                false
+            }
+
+            TypeTerm::Num(_) |
+            TypeTerm::Char(_) |
+            TypeTerm::TypeID(TypeID::Fun(_)) => false
         }
     }
 
+    pub fn strip(self) -> TypeTerm {
+        if self.is_empty() {
+            return TypeTerm::unit();
+        }
 
-    /* strip away empty ladders
-     * & unwrap singletons
-     */
-    pub fn strip(self) -> Self {
         match self {
             TypeTerm::Ladder(rungs) => {
                 let mut rungs :Vec<_> = rungs.into_iter()
@@ -119,22 +410,31 @@ impl TypeTerm {
                     TypeTerm::Ladder(rungs)
                 }
             },
-            TypeTerm::App(args) => {
+            TypeTerm::Spec(args) => {
                 let mut args :Vec<_> = args.into_iter().map(|arg| arg.strip()).collect();
                 if args.len() == 0 {
                     TypeTerm::unit()
                 } else if args.len() == 1 {
                     args.pop().unwrap()
                 } else {
-                    TypeTerm::App(args)
+                    TypeTerm::Spec(args)
                 }
             }
+            TypeTerm::Seq{ mut seq_repr, mut items } => {
+                if let Some(seq_repr) = seq_repr.as_mut() {
+                    *seq_repr = Box::new(seq_repr.clone().strip());
+                }
+                for i in items.iter_mut() {
+                    *i = i.clone().strip();
+                }
+
+                TypeTerm::Seq { seq_repr, items }
+            }
             atom => atom
         }
     }
 
 
-
     pub fn get_interface_type(&self) -> TypeTerm {
         match self {
             TypeTerm::Ladder(rungs) => {
@@ -144,12 +444,142 @@ impl TypeTerm {
                     TypeTerm::unit()
                 }
             }
-            TypeTerm::App(args) => {
-                TypeTerm::App(args.iter().map(|a| a.get_interface_type()).collect())
+            TypeTerm::Spec(args)
+                => TypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()),
+
+            TypeTerm::Func(args)
+                => TypeTerm::Func(args.iter().map(|a| a.get_interface_type()).collect()),
+
+            TypeTerm::Morph(args)
+                => TypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()),
+
+            TypeTerm::Univ(t)
+                => TypeTerm::Univ(Box::new(t.get_interface_type())),
+
+            TypeTerm::Seq { seq_repr, items } => {
+                TypeTerm::Seq {
+                    seq_repr: if let Some(sr) = seq_repr {
+                        Some(Box::new(sr.clone().get_interface_type()))
+                    } else { None },
+                    items: items.iter().map(|t| t.get_interface_type()).collect()
+                }
+            }
+            TypeTerm::Struct { struct_repr, members } => {
+                TypeTerm::Struct {
+                    struct_repr: if let Some(sr) = struct_repr {
+                        Some(Box::new(sr.clone().get_interface_type()))
+                    } else { None },
+                    members: members.iter()
+                        .map(|StructMember{symbol,ty}|
+                            StructMember {symbol:symbol.clone(), ty:ty.get_interface_type() })
+                        .collect()
+                }
+            }
+            TypeTerm::Enum { enum_repr, variants } => {
+                TypeTerm::Enum {
+                    enum_repr: if let Some(sr) = enum_repr {
+                        Some(Box::new(sr.clone().get_interface_type()))
+                    } else { None },
+                    variants: variants.iter()
+                        .map(|EnumVariant{symbol,ty}|
+                            EnumVariant{ symbol:symbol.clone(), ty:ty.get_interface_type() })
+                        .collect()
+                }
+            }
+
+            TypeTerm::TypeID(tyid) => TypeTerm::TypeID(tyid.clone()),
+            TypeTerm::Num(n) => TypeTerm::Num(*n),
+            TypeTerm::Char(c) => TypeTerm::Char(*c)
+        }
+    }
+
+    pub fn get_floor_type(&self) -> (TypeTerm, TypeTerm) {
+        match self.clone() {
+            TypeTerm::Ladder(mut rungs) => {
+                if let Some(bot) = rungs.pop() {
+                    let (bot_ψ, bot_floor) = bot.get_floor_type();
+                    rungs.push(bot_ψ);
+                    (TypeTerm::Ladder(rungs).strip(), bot_floor.strip())
+                } else {
+                    (TypeTerm::unit(), TypeTerm::unit())
+                }
+            }
+            /*
+            SugaredTypeTerm::Spec(args)
+                => (SugaredTypeTerm::SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()),
+
+            SugaredTypeTerm::Func(args)
+                => SugaredTypeTerm::Func(args.iter().map(|a| a.get_floor_type()).collect()),
+
+            SugaredTypeTerm::Morph(args)
+                => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()),
+
+            SugaredTypeTerm::Univ(t)
+                => SugaredTypeTerm::Univ(Box::new(t.get_floor_type())),
+
+            SugaredTypeTerm::Seq { seq_repr, items } => {
+                SugaredTypeTerm::Seq {
+                    seq_repr: if let Some(sr) = seq_repr {
+                        Some(Box::new(sr.clone().get_floor_type()))
+                    } else { None },
+                    items: items.iter().map(|t| t.get_floor_type()).collect()
+                }
+            }
+            SugaredTypeTerm::Struct { struct_repr, members } => {
+                SugaredTypeTerm::Struct {
+                    struct_repr: if let Some(sr) = struct_repr {
+                        Some(Box::new(sr.clone().get_floor_type()))
+                    } else { None },
+                    members: members.iter()
+                        .map(|SugaredStructMember{symbol,ty}|
+                            SugaredStructMember {symbol:symbol.clone(), ty:ty.get_floor_type() })
+                        .collect()
+                }
+            }
+            SugaredTypeTerm::Enum { enum_repr, variants } => {
+                SugaredTypeTerm::Enum {
+                    enum_repr: if let Some(sr) = enum_repr {
+                        Some(Box::new(sr.clone().get_floor_type()))
+                    } else { None },
+                    variants: variants.iter()
+                        .map(|SugaredEnumVariant{symbol,ty}|
+                            SugaredEnumVariant{ symbol:symbol.clone(), ty:ty.get_floor_type() })
+                        .collect()
+                }
+            }
+
+            SugaredTypeTerm::TypeID(tyid) => SugaredTypeTerm::TypeID(tyid.clone()),
+            SugaredTypeTerm::Num(n) => SugaredTypeTerm::Num(*n),
+            SugaredTypeTerm::Char(c) => SugaredTypeTerm::Char(*c)
+            */
+
+            other => (TypeTerm::unit(), other.clone().strip())
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        match self {
+            TypeTerm::TypeID(_) => false,
+            TypeTerm::Num(_) => false,
+            TypeTerm::Char(_) => false,
+            TypeTerm::Univ(t) => t.is_empty(),
+            TypeTerm::Spec(ts) |
+            TypeTerm::Ladder(ts) |
+            TypeTerm::Func(ts) |
+            TypeTerm::Morph(ts) => {
+                ts.iter().fold(true, |s,t| s && t.is_empty() )
+            }
+            TypeTerm::Seq{ seq_repr, items } => {
+                items.iter().fold(true, |s,t| s && t.is_empty() )
+            }
+            TypeTerm::Struct{ struct_repr, members } => {
+                members.iter()
+                    .fold(true, |s,member_decl| s && member_decl.ty.is_empty() )
+            }
+            TypeTerm::Enum{ enum_repr, variants } => {
+                variants.iter()
+                    .fold(true, |s,variant_decl| s && variant_decl.ty.is_empty() )
             }
-            atom => atom.clone()
         }
     }
 }
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/test/curry.rs b/src/test/curry.rs
index a814ab2..aa05b06 100644
--- a/src/test/curry.rs
+++ b/src/test/curry.rs
@@ -9,25 +9,25 @@ fn test_curry() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("<A B C>").unwrap().curry(),
-        dict.parse("<<A B> C>").unwrap()
+        dict.parse_desugared("<A B C>").unwrap().curry(),
+        dict.parse_desugared("<<A B> C>").unwrap()
     );
     assert_eq!(
-        dict.parse("<A B C D>").unwrap().curry(),
-        dict.parse("<<<A B> C> D>").unwrap()
+        dict.parse_desugared("<A B C D>").unwrap().curry(),
+        dict.parse_desugared("<<<A B> C> D>").unwrap()
     );
     assert_eq!(
-        dict.parse("<A B C D E F G H I J K>").unwrap().curry(),
-        dict.parse("<<<<<<<<<<A B> C> D> E> F> G> H> I> J> K>").unwrap()
+        dict.parse_desugared("<A B C D E F G H I J K>").unwrap().curry(),
+        dict.parse_desugared("<<<<<<<<<<A B> C> D> E> F> G> H> I> J> K>").unwrap()
     );
 
     assert_eq!(
-        dict.parse("<A~X B C>").unwrap().curry(),
-        dict.parse("<<A~X B> C>").unwrap()
+        dict.parse_desugared("<A~X B C>").unwrap().curry(),
+        dict.parse_desugared("<<A~X B> C>").unwrap()
     );
     assert_eq!(
-        dict.parse("<A B C~Y~Z> ~ K").unwrap().curry(),
-        dict.parse("< <A B> C~Y~Z > ~ K").unwrap()
+        dict.parse_desugared("<A B C~Y~Z> ~ K").unwrap().curry(),
+        dict.parse_desugared("< <A B> C~Y~Z > ~ K").unwrap()
     );
 }
 
@@ -36,25 +36,25 @@ fn test_decurry() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("<<A B> C>").unwrap().decurry(),
-        dict.parse("<A B C>").unwrap()
+        dict.parse_desugared("<<A B> C>").unwrap().decurry(),
+        dict.parse_desugared("<A B C>").unwrap()
     );
     assert_eq!(
-        dict.parse("<<<A B> C> D>").unwrap().decurry(),
-        dict.parse("<A B C D>").unwrap(),
+        dict.parse_desugared("<<<A B> C> D>").unwrap().decurry(),
+        dict.parse_desugared("<A B C D>").unwrap(),
     );
     assert_eq!(
-        dict.parse("<<<<<<<<<<A B> C> D> E> F> G> H> I> J> K>").unwrap().decurry(),
-        dict.parse("<A B C D E F G H I J K>").unwrap()
+        dict.parse_desugared("<<<<<<<<<<A B> C> D> E> F> G> H> I> J> K>").unwrap().decurry(),
+        dict.parse_desugared("<A B C D E F G H I J K>").unwrap()
     );
 
     assert_eq!(
-        dict.parse("<<A~X B> C>").unwrap().decurry(),
-        dict.parse("<A~X B C>").unwrap()
+        dict.parse_desugared("<<A~X B> C>").unwrap().decurry(),
+        dict.parse_desugared("<A~X B C>").unwrap()
     );
     assert_eq!(
-        dict.parse("<<A~X B> C~Y>~K").unwrap().decurry(),
-        dict.parse("<A~X B C~Y> ~K").unwrap()
+        dict.parse_desugared("<<A~X B> C~Y>~K").unwrap().decurry(),
+        dict.parse_desugared("<A~X B C~Y> ~K").unwrap()
     );
 }
 
diff --git a/src/test/halo.rs b/src/test/halo.rs
index 780b7fd..62729f2 100644
--- a/src/test/halo.rs
+++ b/src/test/halo.rs
@@ -1,39 +1,40 @@
 use crate::{dict::BimapTypeDict, parser::*, unparser::*};
-
+/*
 #[test]
 fn test_common_halo() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
         crate::common_halo(
-            &dict.parse("A~B~C").expect("parse error"),
-            &dict.parse("A~B~C").expect("parse error")
+            &dict.parse_desugared("A~B~C").expect("parse error"),
+            &dict.parse_desugared("A~B~C").expect("parse error")
         ),
-        Some(dict.parse("A~B~C").expect("parse error"))
+        Some(dict.parse_desugared("A~B~C").expect("parse error"))
     );
 
     assert_eq!(
         crate::common_halo(
-            &dict.parse("A~B~X").expect("parse error"),
-            &dict.parse("A~B~Y").expect("parse error")
+            &dict.parse_desugared("A~B~X").expect("parse error"),
+            &dict.parse_desugared("A~B~Y").expect("parse error")
         ),
-        Some(dict.parse("A~B").expect("parse error"))
+        Some(dict.parse_desugared("A~B").expect("parse error"))
     );
 
     assert_eq!(
         crate::common_halo(
-            &dict.parse("A~<B C~D>").expect("parse error"),
-            &dict.parse("A~<B C~E>").expect("parse error")
+            &dict.parse_desugared("A~<B C~D>").expect("parse error"),
+            &dict.parse_desugared("A~<B C~E>").expect("parse error")
         ),
-        Some(dict.parse("A~<B C>").expect("parse error"))
+        Some(dict.parse_desugared("A~<B C>").expect("parse error"))
     );
 
 
     assert_eq!(
             crate::common_halo(
-                &dict.parse("A").expect("parse error"),
-                &dict.parse("A~<B C~E>").expect("parse error")
+                &dict.parse_desugared("A").expect("parse error"),
+                &dict.parse_desugared("A~<B C~E>").expect("parse error")
             ),
-            Some(dict.parse("A").expect("parse error"))
+            Some(dict.parse_desugared("A").expect("parse error"))
         );
 }
+*/
diff --git a/src/test/lnf.rs b/src/test/lnf.rs
deleted file mode 100644
index 4b2a7c2..0000000
--- a/src/test/lnf.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use crate::{dict::{BimapTypeDict}, parser::*};
-
-#[test]
-fn test_flat() {
-    let mut dict = BimapTypeDict::new();
-
-    assert!( dict.parse("A").expect("parse error").is_flat() );
-    assert!( dict.parse("10").expect("parse error").is_flat() );
-    assert!( dict.parse("'x'").expect("parse error").is_flat() );
-    assert!( dict.parse("<A B 23>").expect("parse error").is_flat() );
-    assert!( dict.parse("<A <B C 'x' D>>").expect("parse error").is_flat() );
-
-    assert!( ! dict.parse("A~B").expect("parse error").is_flat() );
-    assert!( ! dict.parse("<A B~C>").expect("parse error").is_flat() );
-    assert!( ! dict.parse("<A <B C~X D>>").expect("parse error").is_flat() );
-}
-
-#[test]
-fn test_normalize() {
-    let mut dict = BimapTypeDict::new();
-
-    assert_eq!(
-        dict.parse("A~B~C").expect("parse error").normalize(),
-        dict.parse("A~B~C").expect("parse errror"),
-    );
-
-    assert_eq!(
-        dict.parse("<A B>~C").expect("parse error").normalize(),
-        dict.parse("<A B>~C").expect("parse errror"),
-    );
-
-    assert_eq!(
-        dict.parse("<A B~C>").expect("parse error").normalize(),
-        dict.parse("<A B>~<A C>").expect("parse errror"),
-    );
-
-    assert_eq!(
-        dict.parse("<A B~C D~E>").expect("parse error").normalize(),
-        dict.parse("<A B D>~<A C D>~<A C E>").expect("parse errror"),
-    );
-
-    assert_eq!(
-        dict.parse("<Seq <Digit 10>~Char>").expect("parse error").normalize(),
-        dict.parse("<Seq <Digit 10>>~<Seq Char>").expect("parse errror"),
-    );
-
-
-    assert_eq!(
-        dict.parse("<A <B C~D~E> F~G H H>").expect("parse error").normalize(),
-        dict.parse("<A <B C> F H H>
-                   ~<A <B D> F H H>
-                   ~<A <B E> F H H>
-                   ~<A <B E> G H H>").expect("parse errror"),
-    );
-
-}
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 1cd4673..0950e3b 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -2,9 +2,8 @@
 pub mod lexer;
 pub mod parser;
 pub mod curry;
-pub mod lnf;
 pub mod pnf;
-pub mod subtype;
+//pub mod subtype;
 pub mod substitution;
 pub mod unification;
 pub mod morphism;
diff --git a/src/test/morphism.rs b/src/test/morphism.rs
index 4754575..0dec101 100644
--- a/src/test/morphism.rs
+++ b/src/test/morphism.rs
@@ -1,10 +1,16 @@
 use {
-    crate::{dict::*, morphism::*, morphism_base::*, morphism_base_sugared::SugaredMorphismBase, morphism_path::*, morphism_path_sugared::SugaredShortestPathProblem, morphism_sugared::{MorphismInstance2, SugaredMorphism, SugaredMorphismType}, parser::*, unparser::*, SugaredTypeTerm, TypeTerm}, std::collections::HashMap
+    crate::{dict::*, morphism_base::MorphismBase,
+        morphism_path::ShortestPathProblem,
+        morphism::{MorphismInstance, Morphism, MorphismType},
+        parser::*, TypeTerm,
+        DesugaredTypeTerm
+    },
+    std::collections::HashMap
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
-fn print_subst(m: &std::collections::HashMap<TypeID, SugaredTypeTerm>, dict: &mut impl TypeDict) {
+fn print_subst(m: &std::collections::HashMap<TypeID, TypeTerm>, dict: &mut impl TypeDict) {
     eprintln!("{{");
 
     for (k,v) in m.iter() {
@@ -17,7 +23,7 @@ fn print_subst(m: &std::collections::HashMap<TypeID, SugaredTypeTerm>, dict: &mu
     eprintln!("}}");
 }
 
-fn print_path(dict: &mut impl TypeDict, path: &Vec<MorphismInstance2<DummyMorphism>>) {
+fn print_path(dict: &mut impl TypeDict, path: &Vec<MorphismInstance<DummyMorphism>>) {
     for n in path.iter() {
         eprintln!("
 morph {}
@@ -34,49 +40,49 @@ with
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-struct DummyMorphism(SugaredMorphismType);
-impl SugaredMorphism for DummyMorphism {
-    fn get_type(&self) -> SugaredMorphismType {
+struct DummyMorphism(MorphismType);
+impl Morphism for DummyMorphism {
+    fn get_type(&self) -> MorphismType {
         self.0.clone()
     }
 }
 
-fn morphism_test_setup() -> ( BimapTypeDict, SugaredMorphismBase<DummyMorphism> ) {
+fn morphism_test_setup() -> ( BimapTypeDict, MorphismBase<DummyMorphism> ) {
     let mut dict = BimapTypeDict::new();
-    let mut base = SugaredMorphismBase::<DummyMorphism>::new();
+    let mut base = MorphismBase::<DummyMorphism>::new();
 
     dict.add_varname("Radix".into());
     dict.add_varname("SrcRadix".into());
     dict.add_varname("DstRadix".into());
 
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
         })
     );
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
         })
     );
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
         })
     );
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
         })
     );
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix>~ℤ_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
         })
     );
 
@@ -87,23 +93,23 @@ fn morphism_test_setup() -> ( BimapTypeDict, SugaredMorphismBase<DummyMorphism>
 fn test_morphism_path1() {
     let (mut dict, mut base) = morphism_test_setup();
 
-    let path = SugaredShortestPathProblem::new(&base, SugaredMorphismType {
-        src_type: dict.parse("<Digit 10> ~ Char").unwrap().sugar(&mut dict),
-        dst_type: dict.parse("<Digit 10> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
+    let path = ShortestPathProblem::new(&base, MorphismType {
+        src_type: dict.parse_desugared("<Digit 10> ~ Char").unwrap().sugar(&mut dict),
+        dst_type: dict.parse_desugared("<Digit 10> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
     }).solve();
 
     assert_eq!(
         path,
         Some(
             vec![
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                        (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType {
-                        src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType {
+                        src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
                     }),
                 }
             ]
@@ -115,26 +121,26 @@ fn test_morphism_path1() {
 fn test_morphism_path2() {
     let (mut dict, mut base) = morphism_test_setup();
 
-    let path = SugaredShortestPathProblem::new(&base, SugaredMorphismType {
-        src_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
-        dst_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+    let path = ShortestPathProblem::new(&base, MorphismType {
+        src_type: dict.parse_desugared("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
+        dst_type: dict.parse_desugared("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
     }).solve();
 
     assert_eq!(
         path,
         Some(
             vec![
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 10 BigEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 10 BigEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
                         }),
                     })
                 }
@@ -147,9 +153,9 @@ fn test_morphism_path2() {
 fn test_morphism_path3() {
     let (mut dict, mut base) = morphism_test_setup();
 
-    let path = SugaredShortestPathProblem::new(&base, SugaredMorphismType {
-        src_type: dict.parse("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
-        dst_type: dict.parse("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+    let path = ShortestPathProblem::new(&base, MorphismType {
+        src_type: dict.parse_desugared("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
+        dst_type: dict.parse_desugared("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
     }).solve();
 
     if let Some(path) = path.as_ref() {
@@ -160,30 +166,30 @@ fn test_morphism_path3() {
         path,
         Some(
             vec![
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
                         }),
                     })
                 },
 
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), SugaredTypeTerm::Num(10)),
-                        (dict.get_typeid(&"DstRadix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), TypeTerm::Num(10)),
+                        (dict.get_typeid(&"DstRadix".into()).unwrap(), TypeTerm::Num(16)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType {
-                        src_type: dict.parse("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType {
+                        src_type: dict.parse_desugared("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
                     }),
                 }
             ]
@@ -196,9 +202,9 @@ fn test_morphism_path3() {
 fn test_morphism_path4() {
     let (mut dict, mut base) = morphism_test_setup();
 
-    let path = SugaredShortestPathProblem::new(&base, SugaredMorphismType {
-        src_type: dict.parse("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
-        dst_type: dict.parse("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ Char>").unwrap().sugar(&mut dict)
+    let path = ShortestPathProblem::new(&base, MorphismType {
+        src_type: dict.parse_desugared("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
+        dst_type: dict.parse_desugared("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ Char>").unwrap().sugar(&mut dict)
     }).solve();
 
     if let Some(path) = path.as_ref() {
@@ -209,44 +215,44 @@ fn test_morphism_path4() {
         path,
         Some(
             vec![
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
                         }),
                     })
                 },
 
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), SugaredTypeTerm::Num(10)),
-                        (dict.get_typeid(&"DstRadix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), TypeTerm::Num(10)),
+                        (dict.get_typeid(&"DstRadix".into()).unwrap(), TypeTerm::Num(16)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType {
-                        src_type: dict.parse("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType {
+                        src_type: dict.parse_desugared("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
                     }),
                 },
 
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 16 LittleEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 16 LittleEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(16)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
                         }),
                     })
                 },
@@ -261,9 +267,9 @@ fn test_morphism_path4() {
 fn test_morphism_path_posint() {
     let (mut dict, mut base) = morphism_test_setup();
 
-    let path = SugaredShortestPathProblem::new(&base, SugaredMorphismType {
-        src_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
-        dst_type: dict.parse("ℕ ~ <PosInt 16 BigEndian> ~ <Seq <Digit 16> ~ Char>").unwrap().sugar(&mut dict),
+    let path = ShortestPathProblem::new(&base, MorphismType {
+        src_type: dict.parse_desugared("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
+        dst_type: dict.parse_desugared("ℕ ~ <PosInt 16 BigEndian> ~ <Seq <Digit 16> ~ Char>").unwrap().sugar(&mut dict),
     }).solve();
 
     if let Some(path) = path.as_ref() {
@@ -274,64 +280,64 @@ fn test_morphism_path_posint() {
         path,
         Some(
             vec![
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 10 BigEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 10 BigEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
                         }),
                     })
                 },
 
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(10)),
+                        (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(10)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType{
-                        src_type: dict.parse("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType{
+                        src_type: dict.parse_desugared("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
                     }),
                 },
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), SugaredTypeTerm::Num(10)),
-                        (dict.get_typeid(&"DstRadix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                        (dict.get_typeid(&"SrcRadix".into()).unwrap(), TypeTerm::Num(10)),
+                        (dict.get_typeid(&"DstRadix".into()).unwrap(), TypeTerm::Num(16)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType{
-                        src_type: dict.parse("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType{
+                        src_type: dict.parse_desugared("ℕ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("ℕ ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
                     }),
                 },
-                MorphismInstance2::Primitive {
+                MorphismInstance::Primitive {
                     σ: vec![
-                        (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                        (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(16)),
                     ].into_iter().collect(),
-                    ψ: SugaredTypeTerm::unit(),
-                    morph: DummyMorphism(SugaredMorphismType{
-                        src_type: dict.parse("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
-                        dst_type: dict.parse("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                    ψ: TypeTerm::unit(),
+                    morph: DummyMorphism(MorphismType{
+                        src_type: dict.parse_desugared("ℕ ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
+                        dst_type: dict.parse_desugared("ℕ ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
                     }),
                 },
 
-                MorphismInstance2::MapSeq {
-                    ψ: dict.parse("ℕ ~ <PosInt 16 BigEndian>").expect("").sugar(&mut dict),
+                MorphismInstance::MapSeq {
+                    ψ: dict.parse_desugared("ℕ ~ <PosInt 16 BigEndian>").expect("").sugar(&mut dict),
                     seq_repr: None,
-                    item_morph: Box::new(MorphismInstance2::Primitive {
+                    item_morph: Box::new(MorphismInstance::Primitive {
                         σ: vec![
-                            (dict.get_typeid(&"Radix".into()).unwrap(), SugaredTypeTerm::Num(16)),
+                            (dict.get_typeid(&"Radix".into()).unwrap(), TypeTerm::Num(16)),
                         ].into_iter().collect(),
-                        ψ: SugaredTypeTerm::unit(),
-                        morph: DummyMorphism(SugaredMorphismType {
-                            src_type: dict.parse("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
-                            dst_type: dict.parse("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
+                        ψ: TypeTerm::unit(),
+                        morph: DummyMorphism(MorphismType {
+                            src_type: dict.parse_desugared("<Digit Radix> ~ ℤ_2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
+                            dst_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
                         }),
                     })
                 },
@@ -343,27 +349,27 @@ fn test_morphism_path_posint() {
 #[test]
 fn morphism_test_seq_repr() {
     let mut dict = BimapTypeDict::new();
-    let mut base = SugaredMorphismBase::<DummyMorphism>::new();
+    let mut base = MorphismBase::<DummyMorphism>::new();
 
     base.add_morphism(
-        DummyMorphism(SugaredMorphismType{
-            src_type: dict.parse("<Seq~<ValueTerminated 0> native.UInt8>").unwrap().sugar(&mut dict),
-            dst_type: dict.parse("<Seq~<LengthPrefix native.UInt64> native.UInt8>").unwrap().sugar(&mut dict)
+        DummyMorphism(MorphismType{
+            src_type: dict.parse_desugared("<Seq~<ValueTerminated 0> native.UInt8>").unwrap().sugar(&mut dict),
+            dst_type: dict.parse_desugared("<Seq~<LengthPrefix native.UInt64> native.UInt8>").unwrap().sugar(&mut dict)
         })
     );
 
     assert_eq!(
-        base.get_morphism_instance(&SugaredMorphismType {
-            src_type: dict.parse("<Seq~<ValueTerminated 0> Char~Ascii~native.UInt8>").expect("parse").sugar(&mut dict),
-            dst_type: dict.parse("<Seq~<LengthPrefix native.UInt64> Char~Ascii~native.UInt8>").expect("parse").sugar(&mut dict)
+        base.get_morphism_instance(&MorphismType {
+            src_type: dict.parse_desugared("<Seq~<ValueTerminated 0> Char~Ascii~native.UInt8>").expect("parse").sugar(&mut dict),
+            dst_type: dict.parse_desugared("<Seq~<LengthPrefix native.UInt64> Char~Ascii~native.UInt8>").expect("parse").sugar(&mut dict)
         }),
         Some(
-            MorphismInstance2::Primitive {
-                ψ: dict.parse("<Seq Char~Ascii>").expect("").sugar(&mut dict),
+            MorphismInstance::Primitive {
+                ψ: dict.parse_desugared("<Seq Char~Ascii>").expect("").sugar(&mut dict),
                 σ: HashMap::new(),
-                morph: DummyMorphism(SugaredMorphismType{
-                    src_type: dict.parse("<Seq~<ValueTerminated 0> native.UInt8>").unwrap().sugar(&mut dict),
-                    dst_type: dict.parse("<Seq~<LengthPrefix native.UInt64> native.UInt8>").unwrap().sugar(&mut dict)
+                morph: DummyMorphism(MorphismType{
+                    src_type: dict.parse_desugared("<Seq~<ValueTerminated 0> native.UInt8>").unwrap().sugar(&mut dict),
+                    dst_type: dict.parse_desugared("<Seq~<LengthPrefix native.UInt64> native.UInt8>").unwrap().sugar(&mut dict)
                 })
             }
         )
diff --git a/src/test/parser.rs b/src/test/parser.rs
index f650ae3..84c1acd 100644
--- a/src/test/parser.rs
+++ b/src/test/parser.rs
@@ -1,6 +1,6 @@
 
 use {
-    crate::{term::*, dict::*, parser::*}
+    crate::{desugared_term::*, dict::*, parser::*, TypeTerm}
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
@@ -42,14 +42,14 @@ fn test_parser_char() {
 fn test_parser_app() {
     assert_eq!(
         BimapTypeDict::new().parse("<A B>"),
-        Ok(TypeTerm::App(vec![
+        Ok(TypeTerm::Spec(vec![
             TypeTerm::TypeID(TypeID::Fun(0)),
             TypeTerm::TypeID(TypeID::Fun(1)),
         ]))
     );
     assert_eq!(
         BimapTypeDict::new().parse("<A B C>"),
-        Ok(TypeTerm::App(vec![
+        Ok(TypeTerm::Spec(vec![
             TypeTerm::TypeID(TypeID::Fun(0)),
             TypeTerm::TypeID(TypeID::Fun(1)),
             TypeTerm::TypeID(TypeID::Fun(2)),
@@ -97,7 +97,7 @@ fn test_parser_ladder_outside() {
     assert_eq!(
         BimapTypeDict::new().parse("<A B>~C"),
         Ok(TypeTerm::Ladder(vec![
-            TypeTerm::App(vec![
+            TypeTerm::Spec(vec![
                 TypeTerm::TypeID(TypeID::Fun(0)),
                 TypeTerm::TypeID(TypeID::Fun(1)),
             ]),
@@ -110,7 +110,7 @@ fn test_parser_ladder_outside() {
 fn test_parser_ladder_inside() {
     assert_eq!(
         BimapTypeDict::new().parse("<A B~C>"),
-        Ok(TypeTerm::App(vec![
+        Ok(TypeTerm::Spec(vec![
             TypeTerm::TypeID(TypeID::Fun(0)),
             TypeTerm::Ladder(vec![
                 TypeTerm::TypeID(TypeID::Fun(1)),
@@ -124,11 +124,11 @@ fn test_parser_ladder_inside() {
 fn test_parser_ladder_between() {
     assert_eq!(
         BimapTypeDict::new().parse("<A B~<C D>>"),
-        Ok(TypeTerm::App(vec![
+        Ok(TypeTerm::Spec(vec![
             TypeTerm::TypeID(TypeID::Fun(0)),
             TypeTerm::Ladder(vec![
                 TypeTerm::TypeID(TypeID::Fun(1)),
-                TypeTerm::App(vec![
+                TypeTerm::Spec(vec![
                     TypeTerm::TypeID(TypeID::Fun(2)),
                     TypeTerm::TypeID(TypeID::Fun(3)),
                 ])
@@ -141,7 +141,7 @@ fn test_parser_ladder_between() {
 #[test]
 fn test_parser_ladder_large() {
     assert_eq!(
-        BimapTypeDict::new().parse(
+        BimapTypeDict::new().parse_desugared(
             "<Seq Date
                   ~<TimeSince UnixEpoch>
                   ~<Duration Seconds>
@@ -154,50 +154,50 @@ fn test_parser_ladder_large() {
               ~<Seq Byte>"),
 
         Ok(
-            TypeTerm::Ladder(vec![
-                TypeTerm::App(vec![
-                    TypeTerm::TypeID(TypeID::Fun(0)),
-                    TypeTerm::Ladder(vec![
-                        TypeTerm::TypeID(TypeID::Fun(1)),
-                        TypeTerm::App(vec![
-                            TypeTerm::TypeID(TypeID::Fun(2)),
-                            TypeTerm::TypeID(TypeID::Fun(3))
+            DesugaredTypeTerm::Ladder(vec![
+                DesugaredTypeTerm::App(vec![
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(0)),
+                    DesugaredTypeTerm::Ladder(vec![
+                        DesugaredTypeTerm::TypeID(TypeID::Fun(1)),
+                        DesugaredTypeTerm::App(vec![
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(2)),
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(3))
                         ]),
-                        TypeTerm::App(vec![
-                            TypeTerm::TypeID(TypeID::Fun(4)),
-                            TypeTerm::TypeID(TypeID::Fun(5))
+                        DesugaredTypeTerm::App(vec![
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(4)),
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(5))
                         ]),
-                        TypeTerm::TypeID(TypeID::Fun(6)),
-                        TypeTerm::App(vec![
-                            TypeTerm::TypeID(TypeID::Fun(7)),
-                            TypeTerm::Num(10),
-                            TypeTerm::TypeID(TypeID::Fun(8))
+                        DesugaredTypeTerm::TypeID(TypeID::Fun(6)),
+                        DesugaredTypeTerm::App(vec![
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(7)),
+                            DesugaredTypeTerm::Num(10),
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(8))
                         ]),
-                        TypeTerm::App(vec![
-                            TypeTerm::TypeID(TypeID::Fun(0)),
-                            TypeTerm::Ladder(vec![
-                                TypeTerm::App(vec![
-                                    TypeTerm::TypeID(TypeID::Fun(9)),
-                                    TypeTerm::Num(10)
+                        DesugaredTypeTerm::App(vec![
+                            DesugaredTypeTerm::TypeID(TypeID::Fun(0)),
+                            DesugaredTypeTerm::Ladder(vec![
+                                DesugaredTypeTerm::App(vec![
+                                    DesugaredTypeTerm::TypeID(TypeID::Fun(9)),
+                                    DesugaredTypeTerm::Num(10)
                                 ]),
-                                TypeTerm::TypeID(TypeID::Fun(10))
+                                DesugaredTypeTerm::TypeID(TypeID::Fun(10))
                             ])
                         ])
                     ])
                 ]),
-                TypeTerm::App(vec![
-                    TypeTerm::TypeID(TypeID::Fun(11)),
-                    TypeTerm::TypeID(TypeID::Fun(10)),
-                    TypeTerm::Char(':')
+                DesugaredTypeTerm::App(vec![
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(11)),
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(10)),
+                    DesugaredTypeTerm::Char(':')
                 ]),
-                TypeTerm::App(vec![
-                    TypeTerm::TypeID(TypeID::Fun(0)),
-                    TypeTerm::TypeID(TypeID::Fun(10))
+                DesugaredTypeTerm::App(vec![
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(0)),
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(10))
                 ]),
-                TypeTerm::TypeID(TypeID::Fun(12)),
-                TypeTerm::App(vec![
-                    TypeTerm::TypeID(TypeID::Fun(0)),
-                    TypeTerm::TypeID(TypeID::Fun(13))
+                DesugaredTypeTerm::TypeID(TypeID::Fun(12)),
+                DesugaredTypeTerm::App(vec![
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(0)),
+                    DesugaredTypeTerm::TypeID(TypeID::Fun(13))
                 ])
             ])
         )
diff --git a/src/test/pnf.rs b/src/test/pnf.rs
index 03c1901..7e76d47 100644
--- a/src/test/pnf.rs
+++ b/src/test/pnf.rs
@@ -5,13 +5,13 @@ fn test_normalize_id() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("A~B~C").expect("parse error").sugar(&mut dict),
-        dict.parse("A~B~C").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("A~B~C").expect("parse error"),
+        dict.parse("A~B~C").expect("parse error").normalize(),
     );
 
     assert_eq!(
-        dict.parse("<A B>~C").expect("parse error").sugar(&mut dict),
-        dict.parse("<A B>~C").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("<A B>~C").expect("parse error"),
+        dict.parse("<A B>~C").expect("parse error").normalize(),
     );
 }
 
@@ -20,23 +20,23 @@ fn test_normalize_spec() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("<A B~C>").expect("parse error").sugar(&mut dict),
-        dict.parse("<A B>~<A C>").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("<A B~C>").expect("parse error"),
+        dict.parse("<A B>~<A C>").expect("parse error").normalize(),
     );
 
     assert_eq!(
-        dict.parse("<A~Y B>").expect("parse error").sugar(&mut dict),
-        dict.parse("<A~Y B>~<Y B>").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("<A~Y B>").expect("parse error"),
+        dict.parse("<A~Y B>~<Y B>").expect("parse error").normalize(),
     );
 
     assert_eq!(
-        dict.parse("<A B~C D~E>").expect("parse error").sugar(&mut dict),
-        dict.parse("<A B D>~<A C D>~<A C E>").expect("parse errror").sugar(&mut dict).normalize(),
+        dict.parse("<A B~C D~E>").expect("parse error"),
+        dict.parse("<A B D>~<A C D>~<A C E>").expect("parse errror").normalize(),
     );
 
     assert_eq!(
-        dict.parse("<A~X B~C D~E>").expect("parse error").sugar(&mut dict),
-        dict.parse("<A~X B D>~<A~X B~C E>~<X C E>").expect("parse errror").sugar(&mut dict).normalize(),
+        dict.parse("<A~X B~C D~E>").expect("parse error"),
+        dict.parse("<A~X B D>~<A~X B~C E>~<X C E>").expect("parse errror").normalize(),
     );
 }
 
@@ -44,25 +44,25 @@ fn test_normalize_spec() {
 fn test_normalize_seq() {
     let mut dict = BimapTypeDict::new();
     assert_eq!(
-        dict.parse("<Seq Char~Ascii>").expect("parse error").sugar(&mut dict),
-        dict.parse("<Seq Char>~<Seq Ascii>").expect("parse errror").sugar(&mut dict).normalize(),
+        dict.parse("<Seq Char~Ascii>").expect("parse error"),
+        dict.parse("<Seq Char>~<Seq Ascii>").expect("parse errror").normalize(),
     );
 
     eprintln!("---------------");
     assert_eq!(
-        dict.parse("<Seq <Digit 10>~Char>").expect("parse error").sugar(&mut dict),
-        dict.parse("<Seq <Digit 10>>~<Seq Char>").expect("parse errror").sugar(&mut dict).normalize(),
+        dict.parse("<Seq <Digit 10>~Char>").expect("parse error"),
+        dict.parse("<Seq <Digit 10>>~<Seq Char>").expect("parse errror").normalize(),
     );
     eprintln!("---------------");
     assert_eq!(
-        dict.parse("<Seq~<ValueDelim '\\0'> Char~Ascii~native.UInt8>").expect("parse error").sugar(&mut dict),
-        dict.parse("<Seq Char> ~ <<ValueDelim '\\0'> Char> ~ <<ValueDelim '\\0'> Ascii~native.UInt8>").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("<Seq~<ValueDelim '\\0'> Char~Ascii~native.UInt8>").expect("parse error"),
+        dict.parse("<Seq Char> ~ <<ValueDelim '\\0'> Char> ~ <<ValueDelim '\\0'> Ascii~native.UInt8>").expect("parse error").normalize(),
     );
 
     eprintln!("---------------");
     assert_eq!(
-        dict.parse("<Seq~<ValueDelim '\\0'> Char~Ascii~native.UInt8>").expect("parse error").sugar(&mut dict),
-        dict.parse("<Seq Char~Ascii> ~ <<ValueDelim '\\0'> Char~Ascii> ~ <<ValueDelim '\\0'> native.UInt8>").expect("parse error").sugar(&mut dict).normalize(),
+        dict.parse("<Seq~<ValueDelim '\\0'> Char~Ascii~native.UInt8>").expect("parse error"),
+        dict.parse("<Seq Char~Ascii> ~ <<ValueDelim '\\0'> Char~Ascii> ~ <<ValueDelim '\\0'> native.UInt8>").expect("parse error").normalize(),
     );
 }
 
@@ -70,10 +70,10 @@ fn test_normalize_seq() {
 fn test_normalize_complex_spec() {
     let mut dict = BimapTypeDict::new();
     assert_eq!(
-        dict.parse("<A~Y <B C~D~E> F H H>").expect("parse error").sugar(&mut dict),
+        dict.parse("<A~Y <B C~D~E> F H H>").expect("parse error"),
         dict.parse("<A~Y <B C> F H H>
                    ~<A~Y <B D> F H H>
-                   ~<Y <B E> F H H>").expect("parse errror").sugar(&mut dict)
+                   ~<Y <B E> F H H>").expect("parse errror")
                .normalize(),
     );
 }
@@ -86,13 +86,13 @@ fn test_normalize_struct() {
                 <  a   TimePoint~<TimeSince UnixEpoch>~Seconds~native.UInt64  >
                 <  b   Angle ~ Degrees ~ ℝ ~ native.Float32 >
             >
-            ").expect("parse error").sugar(&mut dict),
+            ").expect("parse error"),
         dict.parse("
             < Struct <a TimePoint> <b Angle> >
         ~   < Struct  <a <TimeSince UnixEpoch>~Seconds> <b Angle~Degrees~ℝ> >
         ~   < Struct~Aligned  <a native.UInt64> <b native.Float32> >
         ").expect("parse errror")
-            .sugar(&mut dict)
+
             .normalize(),
     );
 }
@@ -105,13 +105,13 @@ fn test_normalize_enum() {
                 <  a   TimePoint~<TimeSince UnixEpoch>~Seconds~native.UInt64  >
                 <  b   Angle ~ Degrees ~ ℝ ~ native.Float32 >
             >
-            ").expect("parse error").sugar(&mut dict),
+            ").expect("parse error"),
         dict.parse("
             < Enum <a TimePoint> <b Angle> >
         ~   < Enum  <a <TimeSince UnixEpoch>~Seconds> <b Angle~Degrees~ℝ> >
         ~   < Enum  <a native.UInt64> <b native.Float32> >
         ").expect("parse errror")
-            .sugar(&mut dict)
+
             .normalize(),
     );
 }
diff --git a/src/test/substitution.rs b/src/test/substitution.rs
index 91aa810..060f2a2 100644
--- a/src/test/substitution.rs
+++ b/src/test/substitution.rs
@@ -1,6 +1,6 @@
 
 use {
-    crate::{dict::*, term::*, parser::*, unparser::*, substitution::*},
+    crate::{dict::*, desugared_term::*, parser::*, unparser::*, substitution::*},
     std::iter::FromIterator,
 };
 
@@ -15,16 +15,16 @@ fn test_subst() {
     // T  -->  ℕ
     σ.insert
         (dict.add_varname(String::from("T")),
-         dict.parse("ℕ").unwrap());
+         dict.parse_desugared("ℕ").unwrap().sugar(&mut dict));
 
     // U  -->  <Seq Char>
     σ.insert
         (dict.add_varname(String::from("U")),
-         dict.parse("<Seq Char>").unwrap());
+         dict.parse_desugared("<Seq Char>").unwrap().sugar(&mut dict));
 
 
     assert_eq!(
-        dict.parse("<Seq T~U>").unwrap().apply_subst(&σ).clone(),
-        dict.parse("<Seq ℕ~<Seq Char>>").unwrap()
+        dict.parse_desugared("<Seq T~U>").unwrap().sugar(&mut dict).apply_subst(&σ).clone(),
+        dict.parse_desugared("<Seq ℕ~<Seq Char>>").unwrap().sugar(&mut dict)
     );
 }
diff --git a/src/test/subtype.rs b/src/test/subtype.rs
index c993063..7591cf6 100644
--- a/src/test/subtype.rs
+++ b/src/test/subtype.rs
@@ -1,31 +1,31 @@
 use crate::{dict::BimapTypeDict, parser::*, unparser::*};
-
+/*
 #[test]
 fn test_semantic_subtype() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("A~B~C").expect("parse error")
+        dict.parse_desugared("A~B~C").expect("parse error")
             .is_semantic_subtype_of(
-                &dict.parse("A~B~C").expect("parse errror")
+                &dict.parse_desugared("A~B~C").expect("parse errror")
             ),
-        Some((0, dict.parse("A~B~C").expect("parse errror")))
+        Some((0, dict.parse_desugared("A~B~C").expect("parse errror")))
     );
 
     assert_eq!(
-        dict.parse("A~B1~C1").expect("parse error")
+        dict.parse_desugared("A~B1~C1").expect("parse error")
             .is_semantic_subtype_of(
-                &dict.parse("A~B2~C2").expect("parse errror")
+                &dict.parse_desugared("A~B2~C2").expect("parse errror")
             ),
-        Some((0, dict.parse("A~B1~C1").expect("parse errror")))
+        Some((0, dict.parse_desugared("A~B1~C1").expect("parse errror")))
     );
 
     assert_eq!(
-        dict.parse("A~B~C1").expect("parse error")
+        dict.parse_desugared("A~B~C1").expect("parse error")
             .is_semantic_subtype_of(
-                &dict.parse("B~C2").expect("parse errror")
+                &dict.parse_desugared("B~C2").expect("parse errror")
             ),
-        Some((1, dict.parse("B~C1").expect("parse errror")))
+        Some((1, dict.parse_desugared("B~C1").expect("parse errror")))
     );
 }
 
@@ -34,63 +34,64 @@ fn test_syntactic_subtype() {
     let mut dict = BimapTypeDict::new();
 
     assert_eq!(
-        dict.parse("A~B~C").expect("parse error")
+        dict.parse_desugared("A~B~C").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("A~B~C").expect("parse errror")
+                &dict.parse_desugared("A~B~C").expect("parse errror")
             ),
         Ok(0)
     );
 
     assert_eq!(
-        dict.parse("A~B~C").expect("parse error")
+        dict.parse_desugared("A~B~C").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("B~C").expect("parse errror")
+                &dict.parse_desugared("B~C").expect("parse errror")
             ),
         Ok(1)
     );
 
     assert_eq!(
-        dict.parse("A~B~C~D~E").expect("parse error")
+        dict.parse_desugared("A~B~C~D~E").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("C~D").expect("parse errror")
+                &dict.parse_desugared("C~D").expect("parse errror")
             ),
         Ok(2)
     );
 
     assert_eq!(
-        dict.parse("A~B~C~D~E").expect("parse error")
+        dict.parse_desugared("A~B~C~D~E").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("C~G").expect("parse errror")
+                &dict.parse_desugared("C~G").expect("parse errror")
             ),
         Err((2,3))
     );
 
     assert_eq!(
-        dict.parse("A~B~C~D~E").expect("parse error")
+        dict.parse_desugared("A~B~C~D~E").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("G~F~K").expect("parse errror")
+                &dict.parse_desugared("G~F~K").expect("parse errror")
             ),
         Err((0,0))
     );
 
     assert_eq!(
-        dict.parse("<Duration Seconds>~ℕ").expect("parse error")
+        dict.parse_desugared("<Duration Seconds>~ℕ").expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("ℕ").expect("parse errror")
+                &dict.parse_desugared("ℕ").expect("parse errror")
             ),
         Ok(1)
     );
 
     assert_eq!(
-        dict.parse("
+        dict.parse_desugared("
 <Duration Seconds>
 ~ℕ
 ~<PosInt 10 BigEndian>
 ~< Seq   <Digit 10> ~ Char >"
         ).expect("parse error")
             .is_syntactic_subtype_of(
-                &dict.parse("<Seq Char>").expect("parse errror")
+                &dict.parse_desugared("<Seq Char>").expect("parse errror")
             ),
         Ok(4)
     );
 }
+*/
diff --git a/src/test/unification.rs b/src/test/unification.rs
index aa20398..64797aa 100644
--- a/src/test/unification.rs
+++ b/src/test/unification.rs
@@ -1,6 +1,6 @@
 
 use {
-    crate::{dict::*, parser::*, unparser::*, term::*, unification::*},
+    crate::{dict::*, parser::*, constraint_system::ConstraintError},
     std::iter::FromIterator
 };
 
@@ -42,7 +42,7 @@ fn test_unification_error() {
             &dict.parse("<B T>").unwrap()
         ),
 
-        Err(UnificationError {
+        Err(ConstraintError {
             addr: vec![0],
             t1: dict.parse("A").unwrap(),
             t2: dict.parse("B").unwrap()
@@ -55,7 +55,7 @@ fn test_unification_error() {
             &dict.parse("<V <U B> T>").unwrap()
         ),
 
-        Err(UnificationError {
+        Err(ConstraintError {
             addr: vec![1, 1],
             t1: dict.parse("A").unwrap(),
             t2: dict.parse("B").unwrap()
@@ -68,7 +68,7 @@ fn test_unification_error() {
             &dict.parse("<Seq T>").unwrap()
         ),
 
-        Err(UnificationError {
+        Err(ConstraintError {
             addr: vec![],
             t1: dict.parse("T").unwrap(),
             t2: dict.parse("<Seq T>").unwrap()
@@ -81,11 +81,15 @@ fn test_unification() {
     test_unify("A", "A", true);
     test_unify("A", "B", false);
     test_unify("<Seq T>", "<Seq Ascii~Char>", true);
-    test_unify("<Seq T>", "<U Char>", true);
+
+    // this worked easily with desugared terms,
+    // but is a weird edge case with sugared terms
+    // not relevant now
+    //test_unify("<Seq T>", "<U Char>", true);
 
     test_unify(
-        "<Seq Path~<Seq Char>>~<SepSeq Char '\n'>~<Seq Char>",
-        "<Seq T~<Seq Char>>~<SepSeq Char '\n'>~<Seq Char>",
+        "<Seq Path~<Seq Char>>~<SepSeq Char '\\n'>~<Seq Char>",
+        "<Seq T~<Seq Char>>~<SepSeq Char '\\n'>~<Seq Char>",
         true
     );
 
@@ -97,9 +101,17 @@ fn test_unification() {
     dict.add_varname(String::from("W"));
 
     assert_eq!(
-        UnificationProblem::new_eq(vec![
-            (dict.parse("U").unwrap(), dict.parse("<Seq Char>").unwrap()),
-            (dict.parse("T").unwrap(), dict.parse("<Seq U>").unwrap()),
+        ConstraintSystem::new_eq(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs: dict.parse("U").unwrap(),
+                rhs: dict.parse("<Seq Char>").unwrap()
+            },
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs: dict.parse("T").unwrap(),
+                rhs: dict.parse("<Seq U>").unwrap()
+            }
         ]).solve(),
         Ok((
             vec![],
@@ -114,9 +126,17 @@ fn test_unification() {
     );
 
     assert_eq!(
-        UnificationProblem::new_eq(vec![
-            (dict.parse("<Seq T>").unwrap(), dict.parse("<Seq W~<Seq Char>>").unwrap()),
-            (dict.parse("<Seq ℕ>").unwrap(), dict.parse("<Seq W>").unwrap()),
+        ConstraintSystem::new_eq(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("<Seq T>").unwrap(),
+                rhs : dict.parse("<Seq W~<Seq Char>>").unwrap()
+            },
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("<Seq ℕ>").unwrap(),
+                rhs : dict.parse("<Seq W>").unwrap(),
+            }
         ]).solve(),
         Ok((
             vec![],
@@ -137,9 +157,12 @@ fn test_subtype_unification1() {
     dict.add_varname(String::from("T"));
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("A ~ B").unwrap(),
-                dict.parse("B").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("A ~ B").unwrap(),
+                rhs : dict.parse("B").unwrap()
+            }
         ]).solve(),
         Ok((
             vec![ dict.parse("A").unwrap() ],
@@ -148,9 +171,12 @@ fn test_subtype_unification1() {
     );
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("A ~ B ~ C ~ D").unwrap(),
-                dict.parse("C ~ D").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("A ~ B ~ C ~ D").unwrap(),
+                rhs : dict.parse("C ~ D").unwrap()
+            }
         ]).solve(),
         Ok((
             vec![ dict.parse("A ~ B").unwrap() ],
@@ -159,22 +185,29 @@ fn test_subtype_unification1() {
     );
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("A ~ B ~ C ~ D").unwrap(),
-                dict.parse("T ~ D").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("A ~ B ~ C ~ D").unwrap(),
+                rhs : dict.parse("T ~ D").unwrap()
+            }
         ]).solve(),
         Ok((
             vec![ TypeTerm::unit() ],
             vec![
-                (dict.get_typeid(&"T".into()).unwrap(), dict.parse("A ~ B ~ C").unwrap())
+                (dict.get_typeid(&"T".into()).unwrap(),
+                    dict.parse("A ~ B ~ C").unwrap())
             ].into_iter().collect()
         ))
     );
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("A ~ B ~ C ~ D").unwrap(),
-                dict.parse("B ~ T ~ D").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("A ~ B ~ C ~ D").unwrap(),
+                rhs : dict.parse("B ~ T ~ D").unwrap(),
+            }
         ]).solve(),
         Ok((
             vec![ dict.parse("A").unwrap() ],
@@ -195,9 +228,12 @@ fn test_subtype_unification2() {
     dict.add_varname(String::from("W"));
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("<Seq~T <Digit 10> ~ Char ~ Ascii>").unwrap(),
-                dict.parse("<Seq~<LengthPrefix x86.UInt64> Char ~ Ascii>").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair{
+                addr: Vec::new(),
+                lhs: dict.parse("<Seq~T <Digit 10> ~ Char ~ Ascii>").unwrap(),
+                rhs: dict.parse("<Seq~<LengthPrefix x86.UInt64> Char ~ Ascii>").unwrap(),
+            }
         ]).solve(),
         Ok((
             vec![
@@ -211,9 +247,17 @@ fn test_subtype_unification2() {
     );
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("U").unwrap(), dict.parse("<Seq Char>").unwrap()),
-            (dict.parse("T").unwrap(), dict.parse("<Seq U>").unwrap()),
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs: dict.parse("U").unwrap(),
+                rhs: dict.parse("<Seq Char>").unwrap()
+            },
+            ConstraintPair {
+                addr : Vec::new(),
+                lhs :  dict.parse("T").unwrap(),
+                rhs : dict.parse("<Seq U>").unwrap(),
+            }
         ]).solve(),
         Ok((
             vec![
@@ -230,18 +274,33 @@ fn test_subtype_unification2() {
         ))
     );
 
-    assert_eq!(
-        UnificationProblem::new_sub(vec![
-            (dict.parse("<Seq T>").unwrap(),
-                dict.parse("<Seq W~<Seq Char>>").unwrap()),
-            (dict.parse("<Seq~<LengthPrefix x86.UInt64> ℕ~<PosInt 10 BigEndian>>").unwrap(),
-                dict.parse("<<LengthPrefix x86.UInt64> W>").unwrap()),
-        ]).solve(),
-        Ok((
+    eprintln!("=&==========&======&=====&=====&==");
+
+    if let Ok((ψ,σ)) =
+        ConstraintSystem::new_sub(vec![
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("<Seq T>").unwrap(),
+                rhs : dict.parse("<Seq W~<Seq Char>>").unwrap(),
+            },
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("<Seq~<LengthPrefix x86.UInt64> ℕ~<PosInt 10 BigEndian>>").unwrap(),
+                rhs : dict.parse("<<LengthPrefix x86.UInt64> W>").unwrap()
+            }
+        ]).solve() {
+            for ( k,v) in σ.iter() {
+                eprintln!(" {:?} ==> {} ",
+                    dict.get_typename(&k),
+                    v.pretty(&dict, 0));
+            }
+
+        assert_eq!(ψ,
             vec![
                 TypeTerm::unit(),
                 dict.parse("<Seq ℕ>").unwrap(),
-            ],
+            ]);
+        assert_eq!(σ,
             vec![
                 // W
                 (TypeID::Var(3), dict.parse("ℕ~<PosInt 10 BigEndian>").unwrap()),
@@ -249,8 +308,10 @@ fn test_subtype_unification2() {
                 // T
                 (TypeID::Var(0), dict.parse("ℕ~<PosInt 10 BigEndian>~<Seq Char>").unwrap())
             ].into_iter().collect()
-        ))
-    );
+        );
+    } else {
+        assert!(false);
+    }
 
     assert_eq!(
         subtype_unify(
@@ -285,7 +346,7 @@ fn test_trait_not_subtype() {
             &dict.parse("A ~ B").expect(""),
             &dict.parse("A ~ B ~ C").expect("")
         ),
-        Err(UnificationError {
+        Err(ConstraintError {
             addr: vec![1],
             t1: dict.parse("B").expect(""),
             t2: dict.parse("C").expect("")
@@ -297,8 +358,8 @@ fn test_trait_not_subtype() {
             &dict.parse("<Seq~List~Vec <Digit 10>~Char>").expect(""),
             &dict.parse("<Seq~List~Vec Char~ReprTree>").expect("")
         ),
-        Err(UnificationError {
-            addr: vec![1,1],
+        Err(ConstraintError {
+            addr: vec![1],
             t1: dict.parse("Char").expect(""),
             t2: dict.parse("ReprTree").expect("")
         })
@@ -333,29 +394,31 @@ pub fn test_subtype_delim() {
     dict.add_varname(String::from("Delim"));
 
     assert_eq!(
-        UnificationProblem::new_sub(vec![
+        ConstraintSystem::new_sub(vec![
 
-            (
+            ConstraintPair {
+                addr: Vec::new(),
                 // given type
-                dict.parse("
+                lhs : dict.parse("
                   < Seq <Seq <Digit 10>~Char~Ascii~UInt8> >
                 ~ < ValueSep ':' Char~Ascii~UInt8 >
                 ~ < Seq~<LengthPrefix UInt64> Char~Ascii~UInt8 >
                 ").expect(""),
 
                 // expected type
-                dict.parse("
+                rhs : dict.parse("
                   < Seq <Seq T> >
                 ~ < ValueSep Delim T >
                 ~ < Seq~<LengthPrefix UInt64> T >
                 ").expect("")
-            ),
+            },
 
             // subtype bounds
-            (
-                dict.parse("T").expect(""),
-                dict.parse("UInt8").expect("")
-            ),
+            ConstraintPair {
+                addr: Vec::new(),
+                lhs : dict.parse("T").expect(""),
+                rhs : dict.parse("UInt8").expect("")
+            },
             /* todo
             (
                 dict.parse("<TypeOf Delim>").expect(""),
@@ -381,7 +444,7 @@ pub fn test_subtype_delim() {
 
 
 
-use crate::{sugar::*, unification_sugared::{SugaredUnificationPair, SugaredUnificationProblem}};
+use crate::{subtype_unify, term::*, constraint_system::{ConstraintPair, ConstraintSystem}};
 
 #[test]
 fn test_list_subtype_sugared() {
@@ -390,25 +453,24 @@ fn test_list_subtype_sugared() {
     dict.add_varname("Item".into());
 
     let subtype_constraints = vec![
-        SugaredUnificationPair::new(
-            dict.parse("<List~Vec <Digit 10>~Char~ReprTree>").expect("").sugar(&mut dict),
-            dict.parse("<List~Vec Item~ReprTree>").expect("").sugar(&mut dict)
+        ConstraintPair::new(
+            dict.parse("<List~Vec <Digit 10>~Char~ReprTree>").expect(""),
+            dict.parse("<List~Vec Item~ReprTree>").expect("")
         )
     ];
 
     assert_eq!(
-        SugaredUnificationProblem::new_sub(subtype_constraints).solve(),
+        ConstraintSystem::new_sub(subtype_constraints).solve(),
         Ok((
-            vec![ SugaredTypeTerm::Ladder(vec![]) ],
+            vec![ TypeTerm::Ladder(vec![]) ],
             vec![
                 (dict.get_typeid(&"Item".into()).unwrap(),
-                    dict.parse("<Digit 10>~Char").unwrap().sugar(&mut dict))
+                    dict.parse("<Digit 10>~Char").unwrap())
             ].into_iter().collect()
         ))
     );
 }
 
-
 #[test]
 pub fn test_subtype_delim_sugared() {
     let mut dict = BimapTypeDict::new();
@@ -417,38 +479,38 @@ pub fn test_subtype_delim_sugared() {
     dict.add_varname(String::from("Delim"));
 
     let subtype_constraints = vec![
-        SugaredUnificationPair::new(
+        ConstraintPair::new(
             dict.parse("
               < Seq <Seq <Digit 10>~Char~Ascii~UInt8> >
             ~ < ValueSep ':' Char~Ascii~UInt8 >
             ~ < Seq~<LengthPrefix UInt64> Char~Ascii~UInt8 >
-            ").expect("").sugar(&mut dict),
+            ").expect(""),
 
             dict.parse("
               < Seq <Seq T> >
             ~ < ValueSep Delim T >
             ~ < Seq~<LengthPrefix UInt64> T >
-            ").expect("").sugar(&mut dict),
+            ").expect(""),
         ),
-        SugaredUnificationPair::new(
-            dict.parse("T").expect("").sugar(&mut dict),
-            dict.parse("UInt8").expect("").sugar(&mut dict),
+        ConstraintPair::new(
+            dict.parse("T").expect(""),
+            dict.parse("UInt8").expect("")
         ),
     ];
 
     assert_eq!(
-        SugaredUnificationProblem::new_sub(subtype_constraints).solve(),
+        ConstraintSystem::new_sub(subtype_constraints).solve(),
         Ok((
             // halo types for each rhs in the sub-equations
             vec![
-                dict.parse("<Seq <Seq <Digit 10>>>").expect("").sugar(&mut dict),
-                dict.parse("Char~Ascii").expect("").sugar(&mut dict),
+                dict.parse("<Seq <Seq <Digit 10>>>").expect(""),
+                dict.parse("Char~Ascii").expect(""),
             ],
 
             // variable substitution
             vec![
-                (dict.get_typeid(&"T".into()).unwrap(), dict.parse("Char~Ascii~UInt8").expect("").sugar(&mut dict)),
-                (dict.get_typeid(&"Delim".into()).unwrap(), SugaredTypeTerm::Char(':')),
+                (dict.get_typeid(&"T".into()).unwrap(), dict.parse("Char~Ascii~UInt8").expect("")),
+                (dict.get_typeid(&"Delim".into()).unwrap(), TypeTerm::Char(':')),
             ].into_iter().collect()
         ))
     );
diff --git a/src/unification.rs b/src/unification.rs
deleted file mode 100644
index 6cbe842..0000000
--- a/src/unification.rs
+++ /dev/null
@@ -1,548 +0,0 @@
-use {
-    crate::{dict::*, term::*}, std::{collections::HashMap, env::consts::ARCH}
-};
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
-
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub struct UnificationError {
-    pub addr: Vec<usize>,
-    pub t1: TypeTerm,
-    pub t2: TypeTerm
-}
-
-#[derive(Clone, Debug)]
-pub struct UnificationPair {
-    addr: Vec<usize>,
-    halo: TypeTerm,
-
-    lhs: TypeTerm,
-    rhs: TypeTerm,
-}
-
-#[derive(Debug)]
-pub struct UnificationProblem {
-    σ: HashMap<TypeID, TypeTerm>,
-    upper_bounds: HashMap< u64, TypeTerm >,
-    lower_bounds: HashMap< u64, TypeTerm >,
-
-    equal_pairs: Vec<UnificationPair>,
-    subtype_pairs: Vec<UnificationPair>,
-    trait_pairs: Vec<UnificationPair>,
-    parallel_pairs: Vec<UnificationPair>
-}
-
-impl UnificationProblem {
-    pub fn new(
-        equal_pairs: Vec<(TypeTerm, TypeTerm)>,
-        subtype_pairs: Vec<(TypeTerm, TypeTerm)>,
-        trait_pairs: Vec<(TypeTerm, TypeTerm)>,
-        parallel_pairs: Vec<(TypeTerm, TypeTerm)>
-    ) -> Self {
-        UnificationProblem {
-            σ: HashMap::new(),
-
-            equal_pairs: equal_pairs.into_iter().map(|(lhs,rhs)|
-                UnificationPair{
-                    lhs,rhs,
-                    halo: TypeTerm::unit(),
-                    addr: Vec::new()
-                }).collect(),
-
-            subtype_pairs: subtype_pairs.into_iter().map(|(lhs,rhs)|
-                UnificationPair{
-                    lhs,rhs,
-                    halo: TypeTerm::unit(),
-                    addr: Vec::new()
-                }).collect(),
-
-            trait_pairs: trait_pairs.into_iter().map(|(lhs,rhs)|
-                UnificationPair{
-                    lhs,rhs,
-                    halo: TypeTerm::unit(),
-                    addr: Vec::new()
-                }).collect(),
-
-            parallel_pairs: parallel_pairs.into_iter().map(|(lhs,rhs)|
-                UnificationPair{
-                    lhs,rhs,
-                    halo: TypeTerm::unit(),
-                    addr: Vec::new()
-                }).collect(),
-
-            upper_bounds: HashMap::new(),
-            lower_bounds: HashMap::new(),
-        }
-    }
-
-    pub fn new_eq(eqs: Vec<(TypeTerm, TypeTerm)>) -> Self {
-        UnificationProblem::new( eqs, Vec::new(), Vec::new(), Vec::new() )
-    }
-
-    pub fn new_sub(subs: Vec<(TypeTerm, TypeTerm)>) -> Self {
-        UnificationProblem::new( Vec::new(), subs, Vec::new(), Vec::new() )
-    }
-
-
-    /// update all values in substitution
-    pub fn reapply_subst(&mut self) {
-        let mut new_σ = HashMap::new();
-        for (v, tt) in self.σ.iter() {
-            let mut tt = tt.clone().normalize();
-            tt.apply_subst(&self.σ);
-            tt = tt.normalize();
-            //eprintln!("update σ : {:?} --> {:?}", v, tt);
-            new_σ.insert(v.clone(), tt);
-        }
-        self.σ = new_σ;
-    }
-
-
-    pub fn eval_equation(&mut self, unification_pair: UnificationPair) -> Result<(), UnificationError> {
-        match (&unification_pair.lhs, &unification_pair.rhs) {
-            (TypeTerm::TypeID(TypeID::Var(varid)), t) |
-            (t, TypeTerm::TypeID(TypeID::Var(varid))) => {
-                if ! t.contains_var( *varid ) {
-                    self.σ.insert(TypeID::Var(*varid), t.clone());
-                    self.reapply_subst();
-                    Ok(())
-                } else if t == &TypeTerm::TypeID(TypeID::Var(*varid)) {
-                    Ok(())
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(*varid)), t2: t.clone() })
-                }
-            }
-
-            (TypeTerm::TypeID(a1), TypeTerm::TypeID(a2)) => {
-                if a1 == a2 { Ok(()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
-            }
-            (TypeTerm::Num(n1), TypeTerm::Num(n2)) => {
-                if n1 == n2 { Ok(()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
-            }
-            (TypeTerm::Char(c1), TypeTerm::Char(c2)) => {
-                if c1 == c2 { Ok(()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
-            }
-
-            (TypeTerm::Ladder(a1), TypeTerm::Ladder(a2)) |
-            (TypeTerm::App(a1), TypeTerm::App(a2)) => {
-                if a1.len() == a2.len() {
-                    for (i, (x, y)) in a1.iter().cloned().zip(a2.iter().cloned()).enumerate().rev() {
-                        let mut new_addr = unification_pair.addr.clone();
-                        new_addr.push(i);
-                        self.equal_pairs.push(
-                            UnificationPair {
-                                lhs: x,
-                                rhs: y,
-                                halo: TypeTerm::unit(),
-                                addr: new_addr
-                            });
-                    }
-                    Ok(())
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
-                }
-            }
-
-            _ => Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
-        }
-    }
-
-
-
-    pub fn add_lower_subtype_bound(&mut self, v: u64, new_lower_bound: TypeTerm) -> Result<(),()> {
-
-        if new_lower_bound == TypeTerm::TypeID(TypeID::Var(v)) {
-            return Ok(());
-        }
-
-        if new_lower_bound.contains_var(v) {
-            // loop
-            return Err(());
-        }
-
-        if let Some(lower_bound) = self.lower_bounds.get(&v).cloned() {
-//                        eprintln!("var already exists. check max. type");
-            if let Ok(halo) = self.eval_subtype(
-                UnificationPair {
-                    lhs: lower_bound.clone(),
-                    rhs: new_lower_bound.clone(),
-                    halo: TypeTerm::unit(),
-                    addr: vec![]
-                }
-            ) {
-//                            eprintln!("found more general lower bound");
-//                            eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone());
-                // generalize variable type to supertype
-                self.lower_bounds.insert(v, new_lower_bound);
-                Ok(())
-            } else if let Ok(halo) = self.eval_subtype(
-                UnificationPair{
-                    lhs: new_lower_bound,
-                    rhs: lower_bound,
-                    halo: TypeTerm::unit(),
-                    addr: vec![]
-                }
-            ) {
-//                            eprintln!("OK, is already larger type");
-                 Ok(())
-            } else {
-//                            eprintln!("violated subtype restriction");
-                Err(())
-            }
-        } else {
-//                        eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone());
-            self.lower_bounds.insert(v, new_lower_bound);
-            Ok(())
-        }
-    }
-
-
-    pub fn add_upper_subtype_bound(&mut self, v: u64, new_upper_bound: TypeTerm) -> Result<(),()> {
-        if new_upper_bound == TypeTerm::TypeID(TypeID::Var(v)) {
-            return Ok(());
-        }
-
-        if new_upper_bound.contains_var(v) {
-            // loop
-            return Err(());
-        }
-
-        if let Some(upper_bound) = self.upper_bounds.get(&v).cloned() {
-            if let Ok(_halo) = self.eval_subtype(
-                UnificationPair {
-                    lhs: new_upper_bound.clone(),
-                    rhs: upper_bound,
-                    halo: TypeTerm::unit(),
-                    addr: vec![]
-                }
-            ) {
-                // found a lower upper bound
-                self.upper_bounds.insert(v, new_upper_bound);
-                Ok(())
-            } else {
-                Err(())
-            }
-        } else {
-            self.upper_bounds.insert(v, new_upper_bound);
-            Ok(())
-        }
-    }
-
-    pub fn eval_subtype(&mut self, unification_pair: UnificationPair) -> Result<
-        // ok: halo type
-        TypeTerm,
-        // error
-        UnificationError
-    > {
-        // eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs);
-        match (unification_pair.lhs.clone(), unification_pair.rhs.clone()) {
-
-            /*
-             Variables
-            */
-
-            (t, TypeTerm::TypeID(TypeID::Var(v))) => {
-                //eprintln!("t <= variable");
-                if self.add_lower_subtype_bound(v, t.clone()).is_ok() {
-                    Ok(TypeTerm::unit())
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(v)), t2: t })
-                }
-            }
-
-            (TypeTerm::TypeID(TypeID::Var(v)), t) => {
-                //eprintln!("variable <= t");
-                if self.add_upper_subtype_bound(v, t.clone()).is_ok() {
-                    Ok(TypeTerm::unit())
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: TypeTerm::TypeID(TypeID::Var(v)), t2: t })
-                }
-            }
-
-
-            /*
-             Atoms
-            */
-
-            (TypeTerm::TypeID(a1), TypeTerm::TypeID(a2)) => {
-                if a1 == a2 { Ok(TypeTerm::unit()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs}) }
-            }
-            (TypeTerm::Num(n1), TypeTerm::Num(n2)) => {
-                if n1 == n2 { Ok(TypeTerm::unit()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
-            }
-            (TypeTerm::Char(c1), TypeTerm::Char(c2)) => {
-                if c1 == c2 { Ok(TypeTerm::unit()) } else { Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) }
-            }
-
-
-            /*
-             Ladders
-            */
-
-            (TypeTerm::Ladder(a1), TypeTerm::Ladder(a2)) => {
-
-                let mut l1_iter = a1.into_iter().enumerate().rev();
-                let mut l2_iter = a2.into_iter().rev();
-
-                let mut halo_ladder = Vec::new();
-
-                while let Some(rhs) = l2_iter.next() {
-                    //eprintln!("take rhs = {:?}", rhs);
-                    if let Some((i, lhs)) = l1_iter.next() {
-                        //eprintln!("take lhs ({}) = {:?}", i, lhs);
-                        let mut addr = unification_pair.addr.clone();
-                        addr.push(i);
-                        //eprintln!("addr = {:?}", addr);
-
-                        match (lhs.clone(), rhs.clone()) {
-                            (t, TypeTerm::TypeID(TypeID::Var(v))) => {
-
-                                if self.add_upper_subtype_bound(v,t.clone()).is_ok() {
-                                    let mut new_upper_bound_ladder = vec![ t ];
-
-                                    if let Some(next_rhs) = l2_iter.next() {
-
-                                        // TODO
-
-                                    } else {
-                                        // take everything
-
-                                        while let Some((i,t)) = l1_iter.next() {
-                                            new_upper_bound_ladder.push(t);
-                                        }
-                                    }
-
-                                    new_upper_bound_ladder.reverse();
-                                    if self.add_upper_subtype_bound(v, TypeTerm::Ladder(new_upper_bound_ladder)).is_ok() {
-                                        // ok
-                                    } else {
-                                        return Err(UnificationError {
-                                            addr,
-                                            t1: lhs,
-                                            t2: rhs
-                                        });
-                                    }
-                                } else {
-                                    return Err(UnificationError {
-                                        addr,
-                                        t1: lhs,
-                                        t2: rhs
-                                    });
-                                }
-                            }
-                            (lhs, rhs) => {
-                                if let Ok(ψ) = self.eval_subtype(
-                                    UnificationPair {
-                                        lhs: lhs.clone(), rhs: rhs.clone(),
-                                        addr:addr.clone(), halo: TypeTerm::unit()
-                                    }
-                                ) {
-                                    // ok.
-                                    //eprintln!("rungs are subtypes. continue");
-                                    halo_ladder.push(ψ);
-                                } else {
-                                    return Err(UnificationError {
-                                        addr,
-                                        t1: lhs,
-                                        t2: rhs
-                                    });
-                                }
-                            }
-                        }
-                    } else {
-                        // not a subtype,
-                        return Err(UnificationError {
-                            addr: vec![],
-                            t1: unification_pair.lhs,
-                            t2: unification_pair.rhs
-                        });
-                    }
-                }
-                //eprintln!("left ladder fully consumed");
-
-                for (i,t) in l1_iter {
-                    halo_ladder.push(t);
-                }
-                halo_ladder.reverse();
-                Ok(TypeTerm::Ladder(halo_ladder).strip().param_normalize())
-            },
-
-            (t, TypeTerm::Ladder(a1)) => {
-                Err(UnificationError{ addr: unification_pair.addr, t1: t, t2: TypeTerm::Ladder(a1) })
-            }
-
-            (TypeTerm::Ladder(mut a1), t) => {
-                let mut new_addr = unification_pair.addr.clone();
-                new_addr.push( a1.len() -1 );
-                if let Ok(halo) = self.eval_subtype(
-                    UnificationPair {
-                        lhs: a1.pop().unwrap(),
-                        rhs: t.clone(),
-                        halo: TypeTerm::unit(),
-                        addr: new_addr
-                    }
-                ) {
-                    a1.push(halo);
-                    if a1.len() == 1 {
-                        Ok(a1.pop().unwrap())
-                    } else {
-                        Ok(TypeTerm::Ladder(a1))
-                    }
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: TypeTerm::Ladder(a1), t2: t })
-                }
-            }
-
-
-            /*
-             Application
-            */
-
-            (TypeTerm::App(a1), TypeTerm::App(a2)) => {
-                if a1.len() == a2.len() {
-                    let mut halo_args = Vec::new();
-                    let mut n_halos_required = 0;
-
-                    for (i, (mut x, mut y)) in a1.iter().cloned().zip(a2.iter().cloned()).enumerate() {
-                        let mut new_addr = unification_pair.addr.clone();
-                        new_addr.push(i);
-
-                        x = x.strip();
-
-//                        eprintln!("before strip: {:?}", y);
-                        y = y.strip();
-//                        eprintln!("after strip: {:?}", y);
-//                        eprintln!("APP<> eval {:?} \n ?<=? {:?} ", x, y);
-
-                        match self.eval_subtype(
-                            UnificationPair {
-                                lhs: x.clone(),
-                                rhs: y.clone(),
-                                halo: TypeTerm::unit(),
-                                addr: new_addr,
-                            }
-                        ) {
-                            Ok(halo) => {
-                            if halo == TypeTerm::unit() {
-                                let mut y = y.clone();
-                                y.apply_subst(&self.σ);
-                                y = y.strip();
-                                let mut top = y.get_lnf_vec().first().unwrap().clone();
-                                halo_args.push(top.clone());
-                                //eprintln!("add top {:?}", top);
-                            } else {
-                                //eprintln!("add halo {:?}", halo);
-                                if n_halos_required > 0 {
-                                    let x = &mut halo_args[n_halos_required-1];
-                                    if let TypeTerm::Ladder(argrs) = x {
-                                        let mut a = a2[n_halos_required-1].clone();
-                                        a.apply_subst(&self.σ);
-                                        a = a.get_lnf_vec().first().unwrap().clone();
-                                        argrs.push(a);
-                                    } else {
-                                        *x = TypeTerm::Ladder(vec![
-                                            x.clone(),
-                                            a2[n_halos_required-1].clone().get_lnf_vec().first().unwrap().clone()
-                                        ]);
-
-                                        x.apply_subst(&self.σ);
-                                    }
-                                }
-
-                                halo_args.push(halo);
-                                n_halos_required += 1;
-                            }
-                            },
-                            Err(err) => { return Err(err); }
-                        }
-                    }
-
-                    if n_halos_required > 0 {
-                        //eprintln!("halo args : {:?}", halo_args);
-                        Ok(TypeTerm::App(halo_args))
-                    } else {
-                        Ok(TypeTerm::unit())
-                    }
-                } else {
-                    Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
-                }
-            }
-
-            _ => Err(UnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs })
-        }
-    }
-
-    pub fn solve(mut self) -> Result<(Vec<TypeTerm>, HashMap<TypeID, TypeTerm>), UnificationError> {
-        // solve equations
-        while let Some( mut equal_pair ) = self.equal_pairs.pop() {
-            equal_pair.lhs.apply_subst(&self.σ);
-            equal_pair.rhs.apply_subst(&self.σ);
-
-            self.eval_equation(equal_pair)?;
-        }
-
-        // solve subtypes
-//        eprintln!("------ SOLVE SUBTYPES ---- ");
-        for mut subtype_pair in self.subtype_pairs.clone().into_iter() {
-            subtype_pair.lhs.apply_subst(&self.σ);
-            subtype_pair.rhs.apply_subst(&self.σ);
-            let _halo = self.eval_subtype( subtype_pair.clone() )?.strip();
-        }
-
-        // add variables from subtype bounds
-        for (var_id, t) in self.upper_bounds.iter() {
-//            eprintln!("VAR {} upper bound {:?}", var_id, t);
-            self.σ.insert(TypeID::Var(*var_id), t.clone().strip());
-        }
-
-        for (var_id, t) in self.lower_bounds.iter() {
-//            eprintln!("VAR {} lower bound {:?}", var_id, t);
-            self.σ.insert(TypeID::Var(*var_id), t.clone().strip());
-        }
-
-        self.reapply_subst();
-
-//        eprintln!("------ MAKE HALOS -----");
-        let mut halo_types = Vec::new();
-        for mut subtype_pair in self.subtype_pairs.clone().into_iter() {
-            subtype_pair.lhs = subtype_pair.lhs.apply_subst(&self.σ).clone().strip();
-            subtype_pair.rhs = subtype_pair.rhs.apply_subst(&self.σ).clone().strip();
-
-            let halo = self.eval_subtype( subtype_pair.clone() )?.strip();
-            halo_types.push(halo);
-        }
-
-        // solve traits
-        while let Some( trait_pair ) = self.trait_pairs.pop() {
-            unimplemented!();
-        }
-
-        Ok((halo_types, self.σ))
-    }
-}
-
-pub fn unify(
-    t1: &TypeTerm,
-    t2: &TypeTerm
-) -> Result<HashMap<TypeID, TypeTerm>, UnificationError> {
-    let unification = UnificationProblem::new_eq(vec![ (t1.clone(), t2.clone()) ]);
-    Ok(unification.solve()?.1)
-}
-
-pub fn subtype_unify(
-    t1: &TypeTerm,
-    t2: &TypeTerm
-) -> Result<(TypeTerm, HashMap<TypeID, TypeTerm>), UnificationError> {
-    let unification = UnificationProblem::new_sub(vec![ (t1.clone(), t2.clone()) ]);
-    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) )
-}
-
-pub fn parallel_unify(
-    t1: &TypeTerm,
-    t2: &TypeTerm
-) -> Result<(TypeTerm, HashMap<TypeID, TypeTerm>), UnificationError> {
-    let unification = UnificationProblem::new(vec![], vec![], vec![], vec![ (t1.clone(), t2.clone()) ]);
-    unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) )
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
diff --git a/src/unparser.rs b/src/unparser.rs
index b78494e..eba2ac9 100644
--- a/src/unparser.rs
+++ b/src/unparser.rs
@@ -1,24 +1,24 @@
-use crate::{dict::*, term::*};
+use crate::{dict::*, desugared_term::*};
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
 
 pub trait UnparseLadderType {
-    fn unparse(&self, t: &TypeTerm) -> String;
+    fn unparse(&self, t: &DesugaredTypeTerm) -> String;
 }
 
 impl<T: TypeDict> UnparseLadderType for T {
-    fn unparse(&self, t: &TypeTerm) -> String {
+    fn unparse(&self, t: &DesugaredTypeTerm) -> String {
         match t {
-            TypeTerm::TypeID(id) => self.get_typename(id).unwrap(),
-            TypeTerm::Num(n) => format!("{}", n),
-            TypeTerm::Char(c) => match c {
+            DesugaredTypeTerm::TypeID(id) => self.get_typename(id).unwrap(),
+            DesugaredTypeTerm::Num(n) => format!("{}", n),
+            DesugaredTypeTerm::Char(c) => match c {
                 '\0' => "'\\0'".into(),
                 '\n' => "'\\n'".into(),
                 '\t' => "'\\t'".into(),
                 '\'' => "'\\''".into(),
                 c => format!("'{}'", c)
             },
-            TypeTerm::Ladder(rungs) => {
+            DesugaredTypeTerm::Ladder(rungs) => {
                 let mut s = String::new();
                 let mut first = true;
                 for r in rungs.iter() {
@@ -30,7 +30,7 @@ impl<T: TypeDict> UnparseLadderType for T {
                 }
                 s
             }
-            TypeTerm::App(args) => {
+            DesugaredTypeTerm::App(args) => {
                 let mut s = String::new();
                 s.push('<');
                 let mut first = true;