// Path: src/main/java/types/TVariable.java
// public class TVariable extends Type {
//     private final String name;
//     private final static HashSet<TVariable> instantiated = new HashSet<>();
// 
//     private TVariable(String name) {
//         this.name = name;
//     }
// 
//     public String name() {
//         return name;
//     }
// 
//     public static TVariable variable(String name) {
//         TVariable var = new TVariable(name);
//         if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//         return var;
//     }
// 
//     public static List<TVariable> variables(String... names) {
//         List<TVariable> variables = new LinkedList<>();
//         for (String name : names) variables.add(new TVariable(name));
//         return variables;
//     }
// 
//     @Override
//     public Type substitute(TVariable var, Type type) {
//         return this.equals(var) ? type : this;
//     }
// 
//     @Override
//     public HashSet<TVariable> ftv() {
//         return new HashSet<>(Collections.singleton(this));
//     }
// 
//     @Override
//     protected Substitution unifyWith(TFunction fun) {
//         return bind(this, fun);
//     }
// 
//     @Override
//     protected Substitution unifyWith(TConstructor cons) {
//         return bind(this, cons);
//     }
// 
//     @Override
//     public Type instantiate(Substitution sub) {
//         return sub.variables().contains(this) ? sub.substituteOf(this) : this;
//     }
// 
//     @Override
//     protected Substitution unifyWith(TVariable var) {
//         return bind(this, var);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         TVariable tVariable = (TVariable) o;
// 
//         return name.equals(tVariable.name);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return ("TVariable_" + name).hashCode();
//     }
// 
//     @Override
//     public String toString() {
//         return name();
//     }
// }
// 
// Path: src/main/java/types/TVariable.java
// public static TVariable variable(String name) {
//     TVariable var = new TVariable(name);
//     if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//     return var;
// }


import types.TVariable;
import static types.TVariable.variable;
package inference.environements;



/**
 * Created by valentin on 24/10/2016.
 */
public class TypeGenerator {
    private int counter = 0;

    public TVariable freshName() {
        char letter = (char) (97 + counter % 26);
        String name = letter + Integer.toString(counter / 26);
        counter++;
// Path: src/main/java/types/TVariable.java
// public class TVariable extends Type {
//     private final String name;
//     private final static HashSet<TVariable> instantiated = new HashSet<>();
// 
//     private TVariable(String name) {
//         this.name = name;
//     }
// 
//     public String name() {
//         return name;
//     }
// 
//     public static TVariable variable(String name) {
//         TVariable var = new TVariable(name);
//         if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//         return var;
//     }
// 
//     public static List<TVariable> variables(String... names) {
//         List<TVariable> variables = new LinkedList<>();
//         for (String name : names) variables.add(new TVariable(name));
//         return variables;
//     }
// 
//     @Override
//     public Type substitute(TVariable var, Type type) {
//         return this.equals(var) ? type : this;
//     }
// 
//     @Override
//     public HashSet<TVariable> ftv() {
//         return new HashSet<>(Collections.singleton(this));
//     }
// 
//     @Override
//     protected Substitution unifyWith(TFunction fun) {
//         return bind(this, fun);
//     }
// 
//     @Override
//     protected Substitution unifyWith(TConstructor cons) {
//         return bind(this, cons);
//     }
// 
//     @Override
//     public Type instantiate(Substitution sub) {
//         return sub.variables().contains(this) ? sub.substituteOf(this) : this;
//     }
// 
//     @Override
//     protected Substitution unifyWith(TVariable var) {
//         return bind(this, var);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         TVariable tVariable = (TVariable) o;
// 
//         return name.equals(tVariable.name);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return ("TVariable_" + name).hashCode();
//     }
// 
//     @Override
//     public String toString() {
//         return name();
//     }
// }
// 
// Path: src/main/java/types/TVariable.java
// public static TVariable variable(String name) {
//     TVariable var = new TVariable(name);
//     if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//     return var;
// }


// Path: src/main/java/inference/environements/TypeGenerator.java
import types.TVariable;
import static types.TVariable.variable;

package inference.environements;



/**
 * Created by valentin on 24/10/2016.
 */
public class TypeGenerator {
    private int counter = 0;

    public TVariable freshName() {
        char letter = (char) (97 + counter % 26);
        String name = letter + Integer.toString(counter / 26);
        counter++;
        return variable(name);