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)); } 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; } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("("); buffer.append(fst); buffer.append(", "); buffer.append(snd); buffer.append(")"); return String.valueOf(buffer); } 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 A { 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); } }