Skip to content

Instantly share code, notes, and snippets.

@rhyskeepence
Created August 7, 2012 11:04
Show Gist options
  • Save rhyskeepence/3284565 to your computer and use it in GitHub Desktop.
Save rhyskeepence/3284565 to your computer and use it in GitHub Desktop.
Scalaz inspired Validation in Java / ewwww
import com.googlecode.totallylazy.Callable1;
import com.googlecode.totallylazy.Callers;
import static sky.sns.bumblebee.io.Regex.regex;
public abstract class Validation<E, A> {
public abstract <X> X fold(final Callable1<E, X> fail, Callable1<A, X> success);
public static <E, A> Validation<E, A> fail(final E e) {
return new Validation<E, A>() {
public <X> X fold(final Callable1<E, X> fail, final Callable1<A, X> success) {
return Callers.call(fail, e);
}
};
}
public static <E, A> Validation<E, A> success(final A a) {
return new Validation<E, A>() {
public <X> X fold(final Callable1<E, X> fail, final Callable1<A, X> success) {
return Callers.call(success, a);
}
};
}
public <B> Validation<E, B> map(final Callable1<A, B> f) {
return new Validation<E, B>() {
public <X> X fold(final Callable1<E, X> fail, final Callable1<B, X> success) {
return Validation.this.fold(fail, new Callable1<A, X>() {
public X call(final A a) {
return Callers.call(success, Callers.call(f, a));
}
});
}
};
}
public <B> Validation<E, B> applicative(final Validation<E, Callable1<A, B>> f, final SemiGroup<E> s) {
return fold(
new Callable1<E, Validation<E, B>>() {
public Validation<E, B> call(final E e1) {
return f.fold(new Callable1<E, Validation<E, B>>() {
public Validation<E, B> call(final E e2) {
return Validation.fail(s.append(e1, e2));
}
}, new Callable1<Callable1<A, B>, Validation<E, B>>() {
public Validation<E, B> call(final Callable1<A, B> f) {
return Validation.fail(e1);
}
}
);
}
}, new Callable1<A, Validation<E, B>>() {
public Validation<E, B> call(final A a) {
return f.fold(new Callable1<E, Validation<E, B>>() {
public Validation<E, B> call(final E e2) {
return Validation.fail(e2);
}
}, new Callable1<Callable1<A, B>, Validation<E, B>>() {
public Validation<E, B> call(final Callable1<A, B> f) {
return Validation.success(Callers.call(f, a));
}
}
);
}
}
);
}
public static void main(String[] args) {
Validation<String, DirectoryNumber> dnValidation = DirectoryNumber.directoryNumber("02012345678");
Validation<String, BatchName> nameValidation = BatchName.of("FirstBatch");
String folded = dnValidation.applicative(nameValidation.map(toBatch()), stringSemigroup()).fold(
new Callable1<String, String>() {
public String call(String errors) throws Exception {
return "Sorry, " + errors;
}
},
new Callable1<Batch, String>() {
public String call(Batch batch) throws Exception {
return "Created " + batch.name + " for " + batch.directoryNumber;
}
}
);
System.out.println(folded);
}
private static Callable1<BatchName, Callable1<DirectoryNumber, Batch>> toBatch() {
return new Callable1<BatchName, Callable1<DirectoryNumber, Batch>>() {
public Callable1<DirectoryNumber, Batch> call(final BatchName name) throws Exception {
return new Callable1<DirectoryNumber, Batch>() {
public Batch call(final DirectoryNumber directoryNumber) throws Exception {
return new Batch(name, directoryNumber);
}
};
}
};
}
private static SemiGroup<String> stringSemigroup() {
return new SemiGroup<String>() {
public String append(String a1, String a2) {
return a1 + " and " + a2;
}
};
}
interface SemiGroup<A> {
A append(A a1, A a2);
}
}
class BatchName {
private final String name;
private BatchName(String name) {
this.name = name;
}
public static Validation<String, BatchName> of(String name) {
if (regex("\\w+").matches(name)) {
return Validation.success(new BatchName(name));
}
return Validation.fail("Batch Name not valid");
}
public String toString() {
return name;
}
}
class DirectoryNumber {
private final String directoryNumber;
private DirectoryNumber(String directoryNumber) {
this.directoryNumber = directoryNumber;
}
public static Validation<String, DirectoryNumber> directoryNumber(String directroyNumber) {
if (regex("0[0-9]{9,10}").matches(directroyNumber)) {
return Validation.success(new DirectoryNumber(directroyNumber));
}
return Validation.fail("Directory Number must be 11-12 digits starting with zero");
}
public String toString() {
return directoryNumber;
}
}
class Batch {
final BatchName name;
final DirectoryNumber directoryNumber;
public Batch(BatchName name, DirectoryNumber directoryNumber) {
this.name = name;
this.directoryNumber = directoryNumber;
}
}
@retronym
Copy link

retronym commented Aug 7, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment