Java code repetition requiring refactoring.
| package RefactoringPuzzle; | |
| abstract class Func<T, U> { | |
| abstract U apply(T t); | |
| } | |
| abstract class IntRdr<A> { | |
| abstract A read(int i); | |
| <B> IntRdr<B> map(final Func<A, B> f) { | |
| return new IntRdr<B>() { | |
| B read(int i) { | |
| return f.apply(IntRdr.this.read(i)); | |
| } | |
| }; | |
| } | |
| <B> IntRdr<B> bind(final Func<A, IntRdr<B>> f) { | |
| return new IntRdr<B>() { | |
| B read(int i) { | |
| return f.apply(IntRdr.this.read(i)).read(i); | |
| } | |
| }; | |
| } | |
| static <A> IntRdr<A> apply(final A a) { | |
| return new IntRdr<A>() { | |
| A read(int _) { | |
| return a; | |
| } | |
| }; | |
| } | |
| } | |
| abstract class Option<A> { | |
| abstract <X> X fold(Func<A, X> some, X none); | |
| <B> Option<B> map(final Func<A, B> f) { | |
| return new Option<B>() { | |
| <X> X fold(final Func<B, X> some, X none) { | |
| return Option.this.fold(new Func<A, X>(){ | |
| X apply(A a) { | |
| return some.apply(f.apply(a)); | |
| } | |
| }, none); | |
| } | |
| }; | |
| } | |
| <B> Option<B> bind(final Func<A, Option<B>> f) { | |
| return new Option<B>() { | |
| <X> X fold(final Func<B, X> some, final X none) { | |
| return Option.this.fold(new Func<A, X>(){ | |
| X apply(A a) { | |
| return f.apply(a).fold(some, none); | |
| } | |
| }, none); | |
| } | |
| }; | |
| } | |
| static <A> Option<A> apply(final A a) { | |
| return new Option<A>() { | |
| <X> X fold(Func<A, X> some, X none) { | |
| return some.apply(a); | |
| } | |
| }; | |
| } | |
| } | |
| abstract class List<A> { | |
| abstract <X> X foldRight(Func<A, Func<X, X>> f, X x); | |
| // Return all the Some values, or None if not all are Some. | |
| static <A> Option<List<A>> runOptions(List<Option<A>> x) { | |
| return x.foldRight(new Func<Option<A>, Func<Option<List<A>>, Option<List<A>>>>(){ | |
| Func<Option<List<A>>, Option<List<A>>> apply(final Option<A> a) { | |
| return new Func<Option<List<A>>, Option<List<A>>>() { | |
| Option<List<A>> apply(final Option<List<A>> b) { | |
| return a.bind(new Func<A, Option<List<A>>>(){ | |
| Option<List<A>> apply(final A aa) { | |
| return b.map(new Func<List<A>, List<A>>(){ | |
| List<A> apply(List<A> bb) { | |
| return bb.prepend(aa); | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| }; | |
| } | |
| }, Option.apply(List.<A>nil())); | |
| } | |
| // Apply an Int to a list of int readers and return the list of return values. | |
| static <A> IntRdr<List<A>> runIntRdrs(List<IntRdr<A>> x) { | |
| return x.foldRight(new Func<IntRdr<A>, Func<IntRdr<List<A>>, IntRdr<List<A>>>>(){ | |
| Func<IntRdr<List<A>>, IntRdr<List<A>>> apply(final IntRdr<A> a) { | |
| return new Func<IntRdr<List<A>>, IntRdr<List<A>>>() { | |
| IntRdr<List<A>> apply(final IntRdr<List<A>> b) { | |
| return a.bind(new Func<A, IntRdr<List<A>>>(){ | |
| IntRdr<List<A>> apply(final A aa) { | |
| return b.map(new Func<List<A>, List<A>>(){ | |
| List<A> apply(List<A> bb) { | |
| return bb.prepend(aa); | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| }; | |
| } | |
| }, IntRdr.apply(List.<A>nil())); | |
| } | |
| List<A> prepend(final A a) { | |
| return new List<A>() { | |
| <X> X foldRight(Func<A, Func<X, X>> f, X x) { | |
| return f.apply(a).apply(this.foldRight(f, x)); | |
| } | |
| }; | |
| } | |
| static <A> List<A> nil() { | |
| return new List<A>() { | |
| <X> X foldRight(Func<A, Func<X, X>> f, X x) { | |
| return x; | |
| } | |
| }; | |
| } | |
| } | |
| // Code Duplication | |
| // *********** ************* ******* ********* | |
| // static <A> Option<List<A>> runOptions(List<Option<A>> x) { | |
| // static <A> IntRdr<List<A>> runIntRdrs(List<IntRdr<A>> x) { | |
| // **************************** ********** *********** ************** | |
| // return x.foldRight(new Func<Option<A>, Func<Option<List<A>>, Option<List<A>>>>(){ | |
| // return x.foldRight(new Func<IntRdr<A>, Func<IntRdr<List<A>>, IntRdr<List<A>>>>(){ | |
| // ***** *********** *********************** ******** | |
| // Func<Option<List<A>>, Option<List<A>>> apply(final Option<A> a) { | |
| // Func<IntRdr<List<A>>, IntRdr<List<A>>> apply(final IntRdr<A> a) { | |
| // **************** *********** ************** | |
| // return new Func<Option<List<A>>, Option<List<A>>>() { | |
| // return new Func<IntRdr<List<A>>, IntRdr<List<A>>>() { | |
| // ********************** ************** | |
| // Option<List<A>> apply(final Option<List<A>> b) { | |
| // IntRdr<List<A>> apply(final IntRdr<List<A>> b) { | |
| // ************************** ************* | |
| // return a.bind(new Func<A, Option<List<A>>>(){ | |
| // return a.bind(new Func<A, IntRdr<List<A>>>(){ | |
| // ***************************** | |
| // Option<List<A>> apply(final A aa) { | |
| // IntRdr<List<A>> apply(final A aa) { | |
| // ****************************************** | |
| // return b.map(new Func<List<A>, List<A>>(){ | |
| // return b.map(new Func<List<A>, List<A>>(){ | |
| // *************************** | |
| // List<A> apply(List<A> bb) { | |
| // List<A> apply(List<A> bb) { | |
| // ********************** | |
| // return bb.prepend(aa); | |
| // return bb.prepend(aa); | |
| // … | |
| // *** *********************** | |
| // }, Option.apply(List.<A>nil())); | |
| // }, IntRdr.apply(List.<A>nil())); | |
| // … |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment