package test0016;

class Seq<E> {
	E head;
	Seq<E> tail;
	Seq() {
		this(null, null);
	}
	boolean isEmpty() {
		return this.tail == null;
	}
	Seq(E head, Seq<E> tail) {
		this.head = head;
		this.tail = tail;
	}
	<T> Seq<Pair<E,T>> zip(Seq<T> that) {
		if (this.isEmpty() || that.isEmpty())
			return new Seq<Pair<E,T>>();
		else
			return new Seq<Pair<E,T>>(
				new Pair<E,T>(this.head, that.head),
					this.tail.zip(that.tail));
	}
	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		if (head != null) {
			buffer.append(head);
		}
		if (tail != null) {
			buffer.append(tail);
		}
		return String.valueOf(buffer);
	}
	public class Zipper<T> {
		Seq<Pair<E,T>> zip(Seq<T> that) {
			if (Seq.this.isEmpty() || that.isEmpty())
				return new Seq<Pair<E,T>>();
			else
				return new Seq<Pair<E,T>>(
					new Pair<E,T>(Seq.this.head, that.head),
						Seq.this.tail.zip(that.tail));
		}
	}
}
class Pair<A, B> {
	A fst;
	B snd;
	
	Pair(A a, B b) {
		this.fst = a;
		this.snd = b;
	}
	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("(");
		buffer.append(fst);
		buffer.append(", ");
		buffer.append(snd);
		buffer.append(")");
		return String.valueOf(buffer);
	}
	@Override
	public boolean equals(Object other) {
		return other instanceof Pair &&
				equals(fst, ((Pair)other).fst) &&
				equals(snd, ((Pair)other).snd);
	}
	private boolean equals(Object x, Object y) {
		return x == null && y == null || x != null && x.equals(y);
	}
}
public class X {
	public static void main(String[] args) {
		Seq<String> strs = new Seq<String>("a", new Seq<String>("b", new Seq<String>()));
		Seq<Number> nums = new Seq<Number>(new Integer(1), new Seq<Number>(new Double(1.5), new Seq<Number>()));
		Seq<String>.Zipper<Number> zipper = strs.new Zipper<Number>();
		Seq<Pair<String,Number>> combined = zipper.zip(nums);
		System.out.println(combined);
	}
}