let unif_combi
   unif_std
   unif_nonstd
  (to_purify   : bool        )
  (u           : term        )
  (v           : term        )
  (subs        : t_subst list)
               : t_subst list =

  let rec unif_combi_help (tas : t_subst list) : t_subst list -> t_subst list =
    function
    | sub::tail ->
        (* Purify u2 and v2. It is also ensured that they are of the same theory
         * afterwards.
         * If they are in the xor theory, at least one of them is Atm(0). *)

        let (u2,v2,sub) = purify_pair to_purify sub (u,v)
        in

        (* Split the substitution into three parts, std_ls, xor_eqns and rem_ls.
         *)

        let (u2,v2,(std_ls,xor_eqns,rem_ls,fv,ctr),std_vars,xor_vars) =
          split_subst sub u2 v2
        in

        (* shared_vars are the variables that occur in std_ls and xor_ls at the
         * same time *)

        let shared_vars = intersection std_vars xor_vars
        in

        (* If u2 and v2 are standard std_subs is the result of unifing u2 and v2
         * with the unif_std. Otherwise std_subs is [(std_ls,fv,[])].
         *
         * xor_eqns contains the remaining xor equations that have to be made
         * equal to Atm(0) by unification in the xor theory. *)

        let (xor_eqns, std_subs) =
          match (u2,v2) with
          | (Atm(0),Atm(0)) -> (xor_eqns, [(std_ls,fv,[])])
          | (Atm(0),Var(n))
          | (Var(n),Atm(0)) ->
              (* add 0 = Var(n) to xor_eqns *)
              ([Var(n)]::xor_eqns, [(std_ls,fv,[])])
          | (Atm(0),Xor(l))
          | (Xor(l),Atm(0)) ->
              (* add 0 = l to xor_eqns *)
              (l::xor_eqns, [(std_ls,fv,[])])
          | _ ->
              (* u2 and v2 are both standard,
               * (u2,v2) = (Xor(_),Xor(_)), (Atm(0),t) or (Xor(_),t) with t
               * standard cannot appear, due to purify_pair *)

              (xor_eqns, unif_std false u2 v2 [(std_ls,fv,[])])
        in

        (if std_subs = [] then
          (* solving the std problem failed, so u and v are not unifiable with
           * respect to sub. Proceed with tail. *)

          unif_combi_help tas tail
        else
          (* Start the breadth first search with the most general layer element
           * (std_subs,vi,[]), so with the trivial variable identif and without
           * layer_ctrs. See comments of process_layer for details.
           *
           * Add the results to tas. *)

          let vi = trivial_part shared_vars
          in
          let tas2 = process_layer unif_std unif_nonstd xor_eqns rem_ls ctr
            [] [] [] tas [(std_subs,vi,[])]
          in
          (* proceed with tail *)
          unif_combi_help tas2 tail
        )
    | [] -> tas
  in
  unif_combi_help [] subs