diff --git a/src/main/scala/lisa/kernel/Printer.scala b/src/main/scala/lisa/kernel/Printer.scala
index 35fb39c1141d25b063e25c0ea833d34734482735..2b3f6df5157aebff8257f571e03e54d4d86f58ed 100644
--- a/src/main/scala/lisa/kernel/Printer.scala
+++ b/src/main/scala/lisa/kernel/Printer.scala
@@ -283,12 +283,12 @@ object Printer {
                             case LeftIff(_, t1, _, _) => pretty("Left ↔", t1)
                             case LeftRefl(_, t1, _) => pretty("L. Refl", t1)
                             case RightRefl(_, _) => pretty("R. Refl")
-                            case LeftSubstEq(_, t1, _, _, _, _) => pretty("L. SubstEq", t1)
-                            case RightSubstEq(_, t1, _, _, _, _) => pretty("R. SubstEq", t1)
-                            case LeftSubstIff(_, t1, _, _, _, _) => pretty("L. SubstIff", t1)
-                            case RightSubstIff(_, t1, _, _, _, _) => pretty("R. SubstIff", t1)
-                            case InstFunSchema(_, t1, _, _, _) => pretty("?Fun Instantiation", t1)
-                            case InstPredSchema(_, t1, _, _, _) => pretty("?Pred Instantiation", t1)
+                            case LeftSubstEq(_, t1, _, _) => pretty("L. SubstEq", t1)
+                            case RightSubstEq(_, t1, _, _) => pretty("R. SubstEq", t1)
+                            case LeftSubstIff(_, t1, _, _) => pretty("L. SubstIff", t1)
+                            case RightSubstIff(_, t1, _, _) => pretty("R. SubstIff", t1)
+                            case InstFunSchema(_, t1, _, _) => pretty("?Fun Instantiation", t1)
+                            case InstPredSchema(_, t1, _, _) => pretty("?Pred Instantiation", t1)
                             case SCSubproof(_, _, false) => pretty("Subproof (hidden)")
                             case other => throw new Exception(s"No available method to print this proof step, consider updating Printer.scala\n$other")
                         }
diff --git a/src/main/scala/lisa/kernel/fol/FOL.scala b/src/main/scala/lisa/kernel/fol/FOL.scala
index 6f09ba07e254e60994196c68795ab58e8278b000..6491a6171eeffcf36f18b9b58838ce5db1a251b9 100644
--- a/src/main/scala/lisa/kernel/fol/FOL.scala
+++ b/src/main/scala/lisa/kernel/fol/FOL.scala
@@ -7,6 +7,7 @@ package lisa.kernel.fol
  * import lisa.fol.FOL._
  * </pre>
  */
-object FOL extends FormulaDefinitions with EquivalenceChecker {
+object FOL extends FormulaDefinitions with EquivalenceChecker with Substitutions {
+
 
 }
diff --git a/src/main/scala/lisa/kernel/fol/FormulaDefinitions.scala b/src/main/scala/lisa/kernel/fol/FormulaDefinitions.scala
index 053be248ab164361b41091eea38be6c92da538ef..16b0c899c4f8c4d496507a4e4233d5df173ee664 100644
--- a/src/main/scala/lisa/kernel/fol/FormulaDefinitions.scala
+++ b/src/main/scala/lisa/kernel/fol/FormulaDefinitions.scala
@@ -66,107 +66,8 @@ private[fol] trait FormulaDefinitions extends FormulaLabelDefinitions with TermD
     override def schematicPredicates: Set[SchematicPredicateLabel] = inner.schematicPredicates
   }
 
-  /**
-   * Performs the substitution of x by r in f. May rename bound variables of f if necessary
-   * to avoid capture of free variables in r.
-   *
-   * @param f The base formula
-   * @param x A variable, which should be free in f
-   * @param r A term that will replace x in f
-   * @return f[r/x]
-   */
-  def substituteVariable(f: Formula, x: VariableLabel, r: Term): Formula = f match {
-    case PredicateFormula(label, args) => PredicateFormula(label, args.map(substituteVariable(_, x, r)))
-    case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(substituteVariable(_, x, r)))
-    case BinderFormula(label, bound, inner) =>
-      if (isSame(bound, x)) f
-      else {
-        val fv = r.freeVariables
-        if (fv.contains(bound)) {
-          val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
-          val newInner = substituteVariable(inner, bound, VariableTerm(newBoundVariable))
-          BinderFormula(label, newBoundVariable, substituteVariable(newInner, x, r))
-        }
-        else BinderFormula(label, bound, substituteVariable(inner, x, r))
-      }
-  }
-
   def bindAll(binder: BinderLabel, vars: Seq[VariableLabel], phi:Formula): Formula =
     vars.foldLeft(phi)((f, v) => BinderFormula(binder, v, f))
 
-  /**
-   * Performs simultaneous substitution of multiple variables by multiple terms in a formula f.
-   *
-   * @param f The base formula
-   * @param m A map from variables to terms.
-   * @return t[m]
-   */
-  def simultaneousSubstitution(f: Formula, m: Map[VariableLabel, Term]): Formula = f match {
-    case PredicateFormula(label, args) => PredicateFormula(label, args.map(simultaneousSubstitution(_, m)))
-    case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(simultaneousSubstitution(_, m)))
-    case BinderFormula(label, bound, inner) =>
-      val newSubst = m - bound
-      val fv = m.values.flatMap(_.freeVariables).toSet
-      if (fv.contains(bound)) {
-        val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
-        val newInner = substituteVariable(inner, bound, VariableTerm(newBoundVariable))
-        BinderFormula(label, newBoundVariable, simultaneousSubstitution(newInner, newSubst))
-      }
-      else BinderFormula(label, bound, simultaneousSubstitution(inner, newSubst))
-  }
-
-  /**
-   * Instantiate a schematic predicate symbol in a formula, using higher-order instantiation.
-   *
-   * @param phi The base formula
-   * @param p   The symbol to replace
-   * @param psi A formula, seen as a function, that will replace p in t.
-   * @param a   The "arguments" of psi when seen as a function rather than a ground formula.
-   *            Those variables are replaced by the actual arguments of p.
-   * @return phi[psi(a1,..., an)/p]
-   */
-  def instantiatePredicateSchema(phi: Formula, p: SchematicPredicateLabel, psi: Formula, a: Seq[VariableLabel]): Formula = {
-    require(a.length == p.arity)
-    phi match {
-      case PredicateFormula(label, args) =>
-        if (isSame(label, p)) simultaneousSubstitution(psi, (a zip args).toMap)
-        else phi
-      case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(instantiatePredicateSchema(_, p, psi, a)))
-      case BinderFormula(label, bound, inner) =>
-        val fv: Set[VariableLabel] = psi.freeVariables -- a
-        if (fv.contains(bound)) {
-          val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
-          val newInner = substituteVariable(inner, bound, VariableTerm(newBoundVariable))
-          BinderFormula(label, newBoundVariable, instantiatePredicateSchema(newInner, p, psi, a))
-        } else BinderFormula(label, bound, instantiatePredicateSchema(inner, p, psi, a))
-    }
-  }
-
-  /**
-   * Instantiate a schematic function symbol in a formula, using higher-order instantiation.
-   *
-   * @param phi The base formula
-   * @param f   The symbol to replace
-   * @param r   A term, seen as a function, that will replace f in t.
-   * @param a   The "arguments" of r when seen as a function rather than a ground term.
-   *            Those variables are replaced by the actual arguments of f.
-   * @return phi[r(a1,..., an)/f]
-   */
-  def instantiateFunctionSchema(phi: Formula, f: SchematicFunctionLabel, r: Term, a: Seq[VariableLabel]): Formula = {
-    require(a.length == f.arity)
-    phi match {
-      case PredicateFormula(label, args) => PredicateFormula(label, args.map(instantiateFunctionSchema(_, f, r, a)))
-      case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(instantiateFunctionSchema(_, f, r, a)))
-      case BinderFormula(label, bound, inner) =>
-        val fv: Set[VariableLabel] = r.freeVariables -- a.toSet
-        if (fv.contains(bound)) {
-          val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
-          val newInner = substituteVariable(inner, bound, VariableTerm(newBoundVariable))
-          BinderFormula(label, newBoundVariable, instantiateFunctionSchema(newInner, f, r, a))
-        } else BinderFormula(label, bound, instantiateFunctionSchema(inner, f, r, a))
-    }
-  }
-
-  def instantiateBinder(f: BinderFormula, t: Term): Formula = substituteVariable(f.inner, f.bound, t)
-
+  
 }
diff --git a/src/main/scala/lisa/kernel/fol/Substitutions.scala b/src/main/scala/lisa/kernel/fol/Substitutions.scala
new file mode 100644
index 0000000000000000000000000000000000000000..5f9d1391b6dcbb9ab77e9efcd63a67d11874180d
--- /dev/null
+++ b/src/main/scala/lisa/kernel/fol/Substitutions.scala
@@ -0,0 +1,182 @@
+package lisa.kernel.fol
+
+trait Substitutions extends FormulaDefinitions{
+
+  /**
+   * A lambda term to express a "term with holes". Main use is to be substituted in place of a function schema.
+   * Morally equivalent to a 2-tuples containing the same informations.
+   * @param vars The names of the "holes" in the term, necessarily of arity 0. The bound variables of the functional term.
+   * @param body The term represented by the object, up to instantiation of the bound schematic variables in args.
+   */
+  case class LambdaTermTerm(vars:Seq[SchematicFunctionLabel], body:Term){
+    require(vars.forall(_.arity == 0))
+    def apply(args:Seq[Term]): Term = instantiateNullaryFunctionSchemas(body, (vars zip args).toMap)
+  }
+
+  /**
+   * A lambda formula to express a "formula with holes". Main use is to be substituted in place of a predicate schema.
+   * Morally equivalent to a 2-tuples containing the same informations.
+   * @param vars The names of the "holes" in a formula, necessarily of arity 0. The bound variables of the functional formula.
+   * @param body The formula represented by the object, up to instantiation of the bound schematic variables in args.
+   */
+  case class LambdaTermFormula(vars:Seq[SchematicFunctionLabel], body:Formula){
+    require(vars.forall(_.arity == 0))
+    def apply(args:Seq[Term]):Formula ={
+      instantiateFunctionSchemas(body, (vars zip (args map(LambdaTermTerm(Nil, _)))).toMap)
+    }
+    //def instantiateFunctionSchemas(phi: Formula, m: Map[SchematicFunctionLabel, LambdaTermTerm]):Formula = ???
+  }
+
+  /**
+   * A lambda formula to express a "formula with holes". Usefull for rules such as Iff substitution
+   * Morally equivalent to a 2-tuples containing the same informations.
+   * @param vars The names of the "holes" in a formula, necessarily of arity 0.
+   * @param body The formula represented by the object, up to instantiation of the bound schematic variables in args.
+   */
+  case class LambdaFormulaFormula(vars:Seq[SchematicPredicateLabel], body:Formula){
+    require(vars.forall(_.arity == 0))
+    def apply(args:Seq[Formula]):Formula = instantiatePredicateSchemas(body, (vars zip (args map(LambdaTermFormula(Nil, _)))).toMap)
+  }
+
+  //////////////////////////
+  // **--- ON TERMS ---** //
+  //////////////////////////
+
+  /**
+   * Performs simultaneous substitution of multiple variables by multiple terms in a term t.
+   * @param t The base term
+   * @param m A map from variables to terms.
+   * @return t[m]
+   */
+  def substituteVariables(t: Term, m: Map[VariableLabel, Term]): Term = t match {
+    case VariableTerm(label) => m.getOrElse(label, t)
+    case FunctionTerm(label, args) => FunctionTerm(label, args.map(substituteVariables(_, m)))
+  }
+
+  /**
+   * Performs simultaneous substitution of multiple nullary schematic function symbols by multiple terms in a base term t.
+   * If one of the symbol is not of arity 0, it will produce an error.
+   * It is needed for the implementation of the general FunctionSchemas instantiation method.
+   * @param t The base term
+   * @param m A map from nullary schematic function label to terms.
+   * @return t[m]
+   */
+  private def instantiateNullaryFunctionSchemas(t: Term, m: Map[SchematicFunctionLabel, Term]): Term = {
+    require(m.forall{ case (symbol, term) => symbol.arity == 0})
+    t match {
+      case VariableTerm(_) => t
+      case FunctionTerm(label, args) => label match
+        case label: SchematicFunctionLabel if label.arity == 0 => m.getOrElse(label, t)
+        case label => FunctionTerm(label, args.map(instantiateNullaryFunctionSchemas(_, m)))
+    }
+  }
+
+  /**
+   * Performs simultaneous substitution of schematic function symbol by "functional" terms, or terms with holes.
+   * If the arity of one of the function symbol to substitute don't match the corresponding number of arguments, or if
+   * one of the "terms with holes" contains a non-nullary symbol, it will produce an error.
+   * @param t The base term
+   * @param m The map from schematic function symbols to "terms with holes". A such term is a pair containing a list of
+   *          nullary schematic function symbols (holes) and a term that is the body of the functional term.
+   * @return t[m]
+   */
+  def instantiateFunctionSchemas(t: Term, m: Map[SchematicFunctionLabel, LambdaTermTerm]): Term = {
+    require(m.forall{case (symbol, LambdaTermTerm(arguments, body)) => arguments.length == symbol.arity})
+    t match {
+      case VariableTerm(_) => t
+      case FunctionTerm(label, args) =>
+        val newArgs = args.map(instantiateFunctionSchemas(_, m))
+        label match
+          case label: ConstantFunctionLabel => FunctionTerm(label, newArgs)
+          case label: SchematicFunctionLabel =>
+            if (m.contains(label))
+              m(label)(newArgs) //= instantiateNullaryFunctionSchemas(m(label).body, (m(label).vars zip newArgs).toMap)
+            else FunctionTerm(label, newArgs)
+
+
+    }
+  }
+
+  /////////////////////////////
+  // **--- ON FORMULAS ---** //
+  /////////////////////////////
+
+  /**
+   * Performs simultaneous substitution of multiple variables by multiple terms in a formula f.
+   *
+   * @param f The base formula
+   * @param m A map from variables to terms.
+   * @return t[m]
+   */
+  def substituteVariables(f: Formula, m: Map[VariableLabel, Term]): Formula = f match {
+    case PredicateFormula(label, args) => PredicateFormula(label, args.map(substituteVariables(_, m)))
+    case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(substituteVariables(_, m)))
+    case BinderFormula(label, bound, inner) =>
+      val newSubst = m - bound
+      val fv = m.values.flatMap(_.freeVariables).toSet
+      if (fv.contains(bound)) {
+        val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
+        val newInner = substituteVariables(inner, Map(bound -> VariableTerm(newBoundVariable)))
+        BinderFormula(label, newBoundVariable, substituteVariables(newInner, newSubst))
+      }
+      else BinderFormula(label, bound, substituteVariables(inner, newSubst))
+  }
+
+  /**
+   * Instantiate a schematic function symbol in a formula, using higher-order instantiation.
+   *
+   * @param phi The base formula
+   * @param f   The symbol to replace
+   * @param r   A term, seen as a function, that will replace f in t.
+   * @param a   The "arguments" of r when seen as a function rather than a ground term.
+   *            Those variables are replaced by the actual arguments of f.
+   * @return phi[r(a1,..., an)/f]
+   */
+  def instantiateFunctionSchemas(phi: Formula, m: Map[SchematicFunctionLabel, LambdaTermTerm]): Formula = {
+    require(m.forall { case (symbol, LambdaTermTerm(arguments, body)) => arguments.length == symbol.arity })
+    phi match {
+      case PredicateFormula(label, args) => PredicateFormula(label, args.map(instantiateFunctionSchemas(_, m)))
+      case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(instantiateFunctionSchemas(_, m)))
+      case BinderFormula(label, bound, inner) =>
+        val fv: Set[VariableLabel] = (m.flatMap {case (symbol, LambdaTermTerm(arguments, body)) => body.freeVariables}).toSet
+        if (fv.contains(bound)) {
+          val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
+          val newInner = substituteVariables(inner, Map(bound -> VariableTerm(newBoundVariable)))
+          BinderFormula(label, newBoundVariable, instantiateFunctionSchemas(newInner, m))
+        } else BinderFormula(label, bound, instantiateFunctionSchemas(inner, m))
+    }
+  }
+
+
+  /**
+   * Instantiate a schematic predicate symbol in a formula, using higher-order instantiation.
+   *
+   * @param phi The base formula
+   * @param p   The symbol to replace
+   * @param psi A formula, seen as a function, that will replace p in t.
+   * @param a   The "arguments" of psi when seen as a function rather than a ground formula.
+   *            Those variables are replaced by the actual arguments of p.
+   * @return phi[psi(a1,..., an)/p]
+   */
+  def instantiatePredicateSchemas(phi: Formula, m: Map[SchematicPredicateLabel, LambdaTermFormula]): Formula = {
+    require(m.forall { case (symbol, LambdaTermFormula(arguments, body)) => arguments.length == symbol.arity })
+    phi match {
+      case PredicateFormula(label, args) =>
+        label match
+          case label: SchematicPredicateLabel if m.contains(label) => m(label)(args)
+          case label => phi
+      case ConnectorFormula(label, args) => ConnectorFormula(label, args.map(instantiatePredicateSchemas(_, m)))
+      case BinderFormula(label, bound, inner) =>
+        val fv: Set[VariableLabel] = (m.flatMap {case (symbol, LambdaTermFormula(arguments, body)) => body.freeVariables}).toSet
+        if (fv.contains(bound)) {
+          val newBoundVariable = VariableLabel(freshId(fv.map(_.name), bound.name))
+          val newInner = substituteVariables(inner, Map(bound -> VariableTerm(newBoundVariable)))
+          BinderFormula(label, newBoundVariable, instantiatePredicateSchemas(newInner, m))
+        } else BinderFormula(label, bound, instantiatePredicateSchemas(inner, m))
+    }
+  }
+
+
+  def instantiateBinder(f: BinderFormula, t: Term): Formula = substituteVariables(f.inner, Map(f.bound -> t))
+
+}
diff --git a/src/main/scala/lisa/kernel/fol/TermDefinitions.scala b/src/main/scala/lisa/kernel/fol/TermDefinitions.scala
index 33a9d54e8457a89b49a195e29f052953a0b8ddf3..c60914864017c0eb0b9fe7a12cad11f9f2a4ea40 100644
--- a/src/main/scala/lisa/kernel/fol/TermDefinitions.scala
+++ b/src/main/scala/lisa/kernel/fol/TermDefinitions.scala
@@ -58,49 +58,6 @@ private[fol] trait TermDefinitions extends TermLabelDefinitions {
     val arity: Int = args.size
   }
 
-  /**
-   * Performs the substitution of x by r in t.
-   *
-   * @param t The base term
-   * @param x A variable, which should be free in t
-   * @param r A term that will replace x in t.
-   * @return t[r/x]
-   */
-  def substituteVariable(t: Term, x: VariableLabel, r: Term): Term = t match {
-    case VariableTerm(label) => if (isSame(label, x)) r else t
-    case FunctionTerm(label, args) => FunctionTerm(label, args.map(substituteVariable(_, x, r)))
-  }
 
-  /**
-   * Performs simultaneous substitution of multiple variables by multiple terms in a term t.
-   *
-   * @param t The base term
-   * @param m A map from variables to terms.
-   * @return t[m]
-   */
-  def simultaneousSubstitution(t: Term, m: Map[VariableLabel, Term]): Term = t match {
-    case VariableTerm(label) => m.getOrElse(label, t)
-    case FunctionTerm(label, args) => FunctionTerm(label, args.map(simultaneousSubstitution(_, m)))
-  }
 
-  /**
-   * instantiate a schematic function symbol in a term, using higher-order instantiation.
-   *
-   * @param t The base term
-   * @param f The symbol to replace
-   * @param r A term, seen as a function, that will replace f in t.
-   * @param a The "arguments" of r when seen as a function rather than a ground term.
-   *          Those variables are replaced by the actual arguments of f.
-   * @return t[r(a1,..., an)/f]
-   */
-  def instantiateFunctionSchema(t: Term, f: SchematicFunctionLabel, r: Term, a: Seq[VariableLabel]): Term = {
-    require(a.length == f.arity)
-    t match {
-      case VariableTerm(label) => t
-      case FunctionTerm(label, args) =>
-        val newArgs = args.map(instantiateFunctionSchema(_, f, r, a))
-        if (isSame(label, f)) simultaneousSubstitution(r, (a zip newArgs).toMap)
-        else FunctionTerm(label, newArgs)
-    }
-  }
 }
diff --git a/src/main/scala/lisa/kernel/proof/SCProofChecker.scala b/src/main/scala/lisa/kernel/proof/SCProofChecker.scala
index 616b2e14537472079bd279ec3e917664fb205ba3..8a1391c0f8f980bcf792a8b4e69d07f8438c5ebc 100644
--- a/src/main/scala/lisa/kernel/proof/SCProofChecker.scala
+++ b/src/main/scala/lisa/kernel/proof/SCProofChecker.scala
@@ -38,14 +38,14 @@ object SCProofChecker {
                  * ------------
                  *    Γ |- Δ
                  */
-                case Rewrite(s, t1) =>
+              case Rewrite(s, t1) =>
                     if (isSameSequent(s, ref(t1))) SCValidProof else SCInvalidProof(Nil, s"The premise and the conclusion are not trivially equivalent.")
                 /*
                  *
                  * --------------
                  *   Γ, φ |- φ, Δ
                  */
-                case Hypothesis(Sequent(left, right), phi) =>
+              case Hypothesis(Sequent(left, right), phi) =>
                     if (contains(left, phi))
                         if (contains(right, phi)) SCValidProof
 
@@ -56,7 +56,7 @@ object SCProofChecker {
                  * ------------------------
                  *       Γ, Σ |-Δ, Π
                  */
-                case Cut(b, t1, t2, phi) =>
+              case Cut(b, t1, t2, phi) =>
                         if (isSameSet(b.left + phi, ref(t1).left union ref(t2).left))
                             if (isSameSet(b.right + phi, ref(t2).right union ref(t1).right))
                                 if (contains(ref(t2).left, phi))
@@ -73,7 +73,7 @@ object SCProofChecker {
                  * --------------     or     -------------
                  *  Γ, φ∧ψ |- Δ               Γ, φ∧ψ |- Δ
                  */
-                case LeftAnd(b, t1, phi, psi) =>
+              case LeftAnd(b, t1, phi, psi) =>
                     if (isSameSet(ref(t1).right, b.right))
                         val phiAndPsi = ConnectorFormula(And, Seq(phi, psi))
                         if (isSameSet(b.left + phi, ref(t1).left + phiAndPsi) ||
@@ -87,7 +87,7 @@ object SCProofChecker {
                  * ------------------------
                  *    Γ, Σ, φ∨ψ |- Δ, Π
                  */
-                case LeftOr(b, t, disjuncts) =>
+              case LeftOr(b, t, disjuncts) =>
                     if (isSameSet(b.right, t.map(ref(_).right).reduce(_ union _)) )
                         val phiOrPsi = ConnectorFormula(Or, disjuncts)
                         if (isSameSet(disjuncts.foldLeft(b.left)(_ + _), t.map(ref(_).left).reduce(_ union _) + phiOrPsi))
@@ -99,7 +99,7 @@ object SCProofChecker {
                  * ------------------------
                  *    Γ, Σ, φ→ψ |- Δ, Π
                  */
-                case LeftImplies(b, t1, t2, phi, psi) =>
+              case LeftImplies(b, t1, t2, phi, psi) =>
                     val phiImpPsi = ConnectorFormula(Implies, Seq(phi, psi))
                     if (isSameSet(b.right + phi, ref(t1).right union ref(t2).right))
                         if (isSameSet(b.left + psi, ref(t1).left union ref(t2).left + phiImpPsi))
@@ -111,7 +111,7 @@ object SCProofChecker {
                  * --------------    or     ---------------
                  *  Γ, φ↔ψ |- Δ              Γ, φ↔ψ |- Δ
                  */
-                case LeftIff(b, t1, phi, psi) =>
+              case LeftIff(b, t1, phi, psi) =>
                     val phiImpPsi = ConnectorFormula(Implies, Seq(phi, psi))
                     val psiImpPhi = ConnectorFormula(Implies, Seq(psi, phi))
                     val phiIffPsi = ConnectorFormula(Iff, Seq(phi, psi))
@@ -128,7 +128,7 @@ object SCProofChecker {
                  * --------------
                  *   Γ, ¬φ |- Δ
                  */
-                case LeftNot(b, t1, phi) =>
+              case LeftNot(b, t1, phi) =>
                     val nPhi = ConnectorFormula(Neg, Seq(phi))
                     if (isSameSet(b.left, ref(t1).left + nPhi))
                         if (isSameSet(b.right + phi, ref(t1).right))
@@ -141,9 +141,9 @@ object SCProofChecker {
                  * -------------------
                  *  Γ, ∀x. φ |- Δ
                  */
-                case LeftForall(b, t1, phi, x, t) =>
+              case LeftForall(b, t1, phi, x, t) =>
                     if (isSameSet(b.right, ref(t1).right))
-                        if (isSameSet(b.left + substituteVariable(phi, x, t), ref(t1).left + BinderFormula(Forall, x, phi)))
+                        if (isSameSet(b.left + substituteVariables(phi, Map(x -> t)), ref(t1).left + BinderFormula(Forall, x, phi)))
                             SCValidProof
                         else SCInvalidProof(Nil, "Left-hand side of conclusion + φ[t/x] must be the same as left-hand side of premise + ∀x. φ")
                     else SCInvalidProof(Nil, "Right-hand side of conclusion must be the same as right-hand side of premise")
@@ -153,7 +153,7 @@ object SCProofChecker {
                  * ------------------- if x is not free in the resulting sequent
                  *  Γ, ∃x. φ|- Δ
                  */
-                case LeftExists(b, t1, phi, x) =>
+              case LeftExists(b, t1, phi, x) =>
                     if (isSameSet(b.right, ref(t1).right))
                         if (isSameSet(b.left + phi, ref(t1).left + BinderFormula(Exists, x, phi)))
                             if ((b.left union b.right).forall(f => !f.freeVariables.contains(x)))
@@ -167,7 +167,7 @@ object SCProofChecker {
                  * ---------------------------- if y is not free in φ
                  *      Γ, ∃!x. φ |- Δ
                  */
-                case LeftExistsOne(b, t1, phi, x) =>
+              case LeftExistsOne(b, t1, phi, x) =>
                     val y = VariableLabel(freshId(phi.freeVariables.map(_.id) + x.id, "y"))
                     val temp = BinderFormula(Exists, y, BinderFormula(Forall, x, ConnectorFormula(Iff, List(PredicateFormula(equality, List(VariableTerm(x), VariableTerm(y))), phi))))
                     if (isSameSet(b.right, ref(t1).right))
@@ -182,7 +182,7 @@ object SCProofChecker {
                  * ------------------------
                  *    Γ, Σ |- φ∧ψ, Π, Δ
                  */
-                case RightAnd(b, t, cunjuncts) =>
+              case RightAnd(b, t, cunjuncts) =>
                     val phiAndPsi = ConnectorFormula(And, cunjuncts)
                     if (isSameSet(b.left, t.map(ref(_).left).reduce(_ union _)))
                         if (isSameSet(cunjuncts.foldLeft(b.right)(_ + _), t.map(ref(_).right).reduce(_ union _) + phiAndPsi))
@@ -194,7 +194,7 @@ object SCProofChecker {
                  * --------------    or    ---------------
                  *  Γ |- φ∨ψ, Δ              Γ |- φ∨ψ, Δ
                  */
-                case RightOr(b, t1, phi, psi) =>
+              case RightOr(b, t1, phi, psi) =>
                     val phiOrPsi = ConnectorFormula(Or, Seq(phi, psi))
                     if (isSameSet(ref(t1).left, b.left))
                         if (isSameSet(b.right + phi, ref(t1).right + phiOrPsi) ||
@@ -208,7 +208,7 @@ object SCProofChecker {
                  * --------------
                  *  Γ |- φ→ψ, Δ
                  */
-                case RightImplies(b, t1, phi, psi) =>
+              case RightImplies(b, t1, phi, psi) =>
                     val phiImpPsi = ConnectorFormula(Implies, Seq(phi, psi))
                     if (isSameSet(ref(t1).left, b.left + phi))
                         if (isSameSet(b.right + psi, ref(t1).right + phiImpPsi))
@@ -220,7 +220,7 @@ object SCProofChecker {
                  * ----------------------------
                  *      Γ, Σ |- φ↔b, Π, Δ
                  */
-                case RightIff(b, t1, t2, phi, psi) =>
+              case RightIff(b, t1, t2, phi, psi) =>
                     val phiImpPsi = ConnectorFormula(Implies, Seq(phi, psi))
                     val psiImpPhi = ConnectorFormula(Implies, Seq(psi, phi))
                     val phiIffPsi = ConnectorFormula(Iff, Seq(phi, psi))
@@ -234,7 +234,7 @@ object SCProofChecker {
                  * --------------
                  *   Γ |- ¬φ, Δ
                  */
-                case RightNot(b, t1, phi) =>
+              case RightNot(b, t1, phi) =>
                     val nPhi = ConnectorFormula(Neg, Seq(phi))
                     if (isSameSet(b.right, ref(t1).right + nPhi))
                         if (isSameSet(b.left + phi, ref(t1).left))
@@ -246,7 +246,7 @@ object SCProofChecker {
                  * ------------------- if x is not free in the resulting sequent
                  *  Γ |- ∀x. φ, Δ
                  */
-                case RightForall(b, t1, phi, x) =>
+              case RightForall(b, t1, phi, x) =>
                     if (isSameSet(b.left, ref(t1).left))
                         if (isSameSet(b.right + phi, ref(t1).right + BinderFormula(Forall, x ,phi)))
                             if ((b.left union b.right).forall(f => !f.freeVariables.contains(x)))
@@ -259,9 +259,9 @@ object SCProofChecker {
                  * -------------------
                  *  Γ |- ∃x. φ, Δ
                  */
-                case RightExists(b, t1, phi, x, t) =>
+              case RightExists(b, t1, phi, x, t) =>
                     if (isSameSet(b.left, ref(t1).left))
-                        if (isSameSet(b.right + substituteVariable(phi, x, t), ref(t1).right + BinderFormula(Exists, x ,phi)))
+                        if (isSameSet(b.right + substituteVariables(phi, Map(x -> t)), ref(t1).right + BinderFormula(Exists, x ,phi)))
                             SCValidProof
                         else SCInvalidProof(Nil, "Right-hand side of the conclusion + φ[t/x] must be the same as right-hand side of the premise + ∃x. φ")
                     else SCInvalidProof(Nil, "Left-hand sides or conclusion and premise must be the same.")
@@ -273,7 +273,7 @@ object SCProofChecker {
                  *      Γ|- ∃!x. φ,  Δ
                  * </pre>
                  */
-                case RightExistsOne(b, t1, phi, x) =>
+              case RightExistsOne(b, t1, phi, x) =>
                     val y = VariableLabel(freshId(phi.freeVariables.map(_.id), "x"))
                     val temp = BinderFormula(Exists, y, BinderFormula(Forall, x, ConnectorFormula(Iff, List(PredicateFormula(equality, List(VariableTerm(x), VariableTerm(y))), phi))))
                     if (isSameSet(b.left, ref(t1).left))
@@ -289,7 +289,7 @@ object SCProofChecker {
                  * --------------
                  *   Γ, Σ |- Δ
                  */
-                case Weakening(b, t1) =>
+              case Weakening(b, t1) =>
                     if (isSubset(ref(t1).left, b.left))
                         if (isSubset(ref(t1).right, b.right))
                             SCValidProof
@@ -302,7 +302,7 @@ object SCProofChecker {
                  * --------------
                  *     Γ |- Δ
                  */
-                case LeftRefl(b, t1, phi) =>
+              case LeftRefl(b, t1, phi) =>
                     phi match {
                         case PredicateFormula(`equality`, Seq(left, right)) =>
                             if (isSame(left, right))
@@ -320,7 +320,7 @@ object SCProofChecker {
                  * --------------
                  *     |- s=s
                  */
-                case RightRefl(b, phi) =>
+              case RightRefl(b, phi) =>
                     phi match {
                         case PredicateFormula(`equality`, Seq(left, right)) =>
                             if (isSame(left, right))
@@ -336,7 +336,8 @@ object SCProofChecker {
                  * ---------------------
                  *  Γ, s=t, φ[t/?f] |- Δ
                  */
-                case LeftSubstEq(b, t1, s, t, phi, f) =>
+              case LeftSubstEq(b, t1, s, t, phi, f) =>
+              case LeftSubstEq(b, t1, equals, lambdaPhi) =>
                     val sEqT = PredicateFormula(equality, Seq(s, t))
                     val phi_s_for_f = instantiateFunctionSchema(phi, f, s, Nil)
                     val phi_t_for_f = instantiateFunctionSchema(phi, f, t, Nil)
@@ -355,7 +356,7 @@ object SCProofChecker {
                  * ---------------------
                  *  Γ, s=t |- φ[t/?f], Δ
                  */
-                case RightSubstEq(b, t1, s, t, phi, f) =>
+              case RightSubstEq(b, t1, s, t, phi, f) =>
                     val sEqt = PredicateFormula(equality, Seq(s, t))
                     if (f.arity == 0)
                         if (isSameSet(ref(t1).left + sEqt, b.left))
@@ -372,7 +373,7 @@ object SCProofChecker {
                  * ---------------------
                  *  Γ, ψ↔τ, φ[τ/?q] |- Δ
                  */
-                case LeftSubstIff(b, t1, psi, tau, phi, q) =>
+              case LeftSubstIff(b, t1, psi, tau, phi, q) =>
                     val psiIffTau = ConnectorFormula(Iff, Seq(psi, tau))
                     val phi_tau_for_q = instantiatePredicateSchema(phi, q, tau, Nil)
                     val phi_psi_for_q = instantiatePredicateSchema(phi, q, psi, Nil)
@@ -390,7 +391,7 @@ object SCProofChecker {
                  * ---------------------
                  *  Γ, ψ↔τ |- φ[τ/?p], Δ
                  */
-                case RightSubstIff(b, t1, psi, tau, phi, q) =>
+              case RightSubstIff(b, t1, psi, tau, phi, q) =>
                     val psiIffTau = ConnectorFormula(Iff, Seq(psi, tau))
                     val phi_tau_for_q = instantiatePredicateSchema(phi, q, tau, Nil)
                     val phi_psi_for_q = instantiatePredicateSchema(phi, q, psi, Nil)
@@ -409,7 +410,7 @@ object SCProofChecker {
                  *  Γ[r(a)/?f] |- Δ[r(a)/?f]
                  * </pre>
                  */
-                case InstFunSchema(bot, t1, f, r, a) =>
+              case InstFunSchema(bot, t1, f, r, a) =>
                     val expected = (ref(t1).left.map(phi => instantiateFunctionSchema(phi, f, r, a)), ref(t1).right.map(phi => instantiateFunctionSchema(phi, f, r, a)))
                     if (isSameSet(bot.left, expected._1))
                         if (isSameSet(bot.right, expected._2))
@@ -424,7 +425,7 @@ object SCProofChecker {
                  *  Γ[ψ(a)/?p] |- Δ[ψ(a)/?p]
                  * </pre>
                  */
-                case InstPredSchema(bot, t1, p, psi, a) =>
+              case InstPredSchema(bot, t1, p, psi, a) =>
                     val expected = (ref(t1).left.map(phi => instantiatePredicateSchema(phi, p, psi, a)), ref(t1).right.map(phi => instantiatePredicateSchema(phi, p, psi, a)))
                     if (isSameSet(bot.left, expected._1))
                         if (isSameSet(bot.right, expected._2))
@@ -433,7 +434,7 @@ object SCProofChecker {
                             SCInvalidProof(Nil, "Right-hand side of premise instantiated with [?p/ψ(a)] must be the same as right-hand side of conclusion.")
                     else  SCInvalidProof(Nil, "Left-hand side of premise instantiated with [?p/ψ(a)] must be the same as left-hand side of conclusion.")
 
-                case SCSubproof(sp, premises, _) =>
+              case SCSubproof(sp, premises, _) =>
                     if (premises.size == sp.imports.size){
                         val invalid = premises.zipWithIndex.find((no, p) => !isSameSequent(ref(no), sp.imports(p)) )
                         if (invalid.isEmpty){
diff --git a/src/main/scala/lisa/kernel/proof/SequentCalculus.scala b/src/main/scala/lisa/kernel/proof/SequentCalculus.scala
index 1166e1c46705195f1235e4b6090952d4542464d1..8f20615690428b2a55d4f68400cbdc1483943ed7 100644
--- a/src/main/scala/lisa/kernel/proof/SequentCalculus.scala
+++ b/src/main/scala/lisa/kernel/proof/SequentCalculus.scala
@@ -247,36 +247,36 @@ object SequentCalculus {
     case class RightRefl(bot: Sequent, fa: Formula) extends SCProofStep{val premises = Seq()}
     /**
      * <pre>
-     *    Γ, φ[s/?f] |- Δ
+     *    Γ, φ(s1,...,sn) |- Δ
      * ---------------------
-     *  Γ, s=t, φ[t/?f ] |- Δ
+     *  Γ, s1=t1, ..., sn=tn, φ(t1,...tn) |- Δ
      * </pre>
      */
-    case class LeftSubstEq(bot: Sequent, t1: Int, s: Term, t: Term, phi: Formula, f: SchematicFunctionLabel) extends SCProofStep{val premises = Seq(t1)}
+    case class LeftSubstEq(bot: Sequent, t1: Int, equals: List[(Term, Term)], lambdaPhi:LambdaTermFormula) extends SCProofStep{val premises = Seq(t1)}
     /**
      * <pre>
-     *    Γ |- φ[s/?f], Δ
+     *    Γ |- φ(s1,...,sn), Δ
      * ---------------------
-     *  Γ, s=t |- φ[t/?f], Δ
+     *  Γ, s1=t1, ..., sn=tn |- φ(t1,...tn), Δ
      * </pre>
      */
-    case class RightSubstEq(bot: Sequent, t1: Int, s: Term, t: Term, phi: Formula, f: SchematicFunctionLabel) extends SCProofStep{val premises = Seq(t1)}
+    case class RightSubstEq(bot: Sequent, t1: Int, equals: List[(Term, Term)] ,lambdaPhi:LambdaTermFormula) extends SCProofStep{val premises = Seq(t1)}
     /**
      * <pre>
-     *    Γ, φ[a/?p] |- Δ
+     *    Γ, φ(a1,...an) |- Δ
      * ---------------------
-     *  Γ, a↔b, φ[b/?p] |- Δ
+     *  Γ, a1↔b1, ..., an↔bn, φ(b1,...bn) |- Δ
      * </pre>
      */
-    case class LeftSubstIff(bot: Sequent, t1: Int, fa: Formula, fb: Formula, phi: Formula, h: SchematicPredicateLabel) extends SCProofStep{val premises = Seq(t1)}
+    case class LeftSubstIff(bot: Sequent, t1: Int, equals: List[(Formula, Formula)], lambdaPhi:LambdaFormulaFormula) extends SCProofStep{val premises = Seq(t1)}
     /**
      * <pre>
-     *    Γ |- φ[a/?p], Δ
+     *    Γ |- φ(a1,...an), Δ
      * ---------------------
-     *  Γ, a↔b |- φ[b/?p], Δ
+     *  Γ, a1↔b1, ..., an↔bn |- φ(b1,...bn), Δ
      * </pre>
      */
-    case class RightSubstIff(bot: Sequent, t1: Int, fa: Formula, fb: Formula, phi: Formula, h: SchematicPredicateLabel) extends SCProofStep{val premises = Seq(t1)}
+    case class RightSubstIff(bot: Sequent, t1: Int, equals: List[(Formula, Formula)], lambdaPhi:LambdaFormulaFormula) extends SCProofStep{val premises = Seq(t1)}
     /**
      * <pre>
      *           Γ |- Δ
@@ -284,7 +284,7 @@ object SequentCalculus {
      *  Γ[r(a)/?f] |- Δ[r(a)/?f]
      * </pre>
      */
-    case class InstFunSchema(bot:Sequent, t1:Int, f:SchematicFunctionLabel, r:Term, a: Seq[VariableLabel] ) extends SCProofStep{val premises = Seq(t1)}
+    case class InstFunSchema(bot:Sequent, t1:Int, f:SchematicFunctionLabel, lambdaT: LambdaTermTerm ) extends SCProofStep{val premises = Seq(t1)}
     /**
      * <pre>
      *           Γ |- Δ
@@ -292,7 +292,7 @@ object SequentCalculus {
      *  Γ[ψ(a)/?p] |- Δ[ψ(a)/?p]
      * </pre>
      */
-    case class InstPredSchema(bot:Sequent, t1:Int, p:SchematicPredicateLabel, psi:Formula, a: Seq[VariableLabel] ) extends SCProofStep{val premises = Seq(t1)}
+    case class InstPredSchema(bot:Sequent, t1:Int, p:SchematicPredicateLabel, lambdaPhi:LambdaTermFormula ) extends SCProofStep{val premises = Seq(t1)}
 
     // Proof Organisation rules
     case class SCSubproof(sp: SCProof, premises: Seq[Int] = Seq.empty, display:Boolean = true) extends SCProofStep {