Created
August 7, 2012 11:04
-
-
Save rhyskeepence/3284565 to your computer and use it in GitHub Desktop.
Scalaz inspired Validation in Java / ewwww
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's one we prepared earlier...
https://github.com/functionaljava/functionaljava/blob/master/core/src/main/java/fj/data/Validation.java