Java optional: map to subclass or else super class - java

I am trying to re-write a scala example of a POC project from Manning's "Akka in Action" in Java. The project is a small Http server for creating events and buying tickets.
I am at a point when an actor can send an Optional<Event> to my RestApi. Depending on whether the value is present I should complete the call with OK, else NOT_FOUND.
In Scala the snippet looks as follow:
get {
// GET /events/:event
onSuccess(getEvent(event)) {
_.fold(complete(NotFound))(e => complete(OK, e))
}
}
...where getEvent returns an Option[Event] (equivalent of java's Optional<Event>). This is how I rewrote it in Java:
get(() -> onSuccess(() -> getEvent(event), eventGetRoute()))
...
//and eventGetRoute() is a function:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> maybeEvent.map(event -> complete(OK, event, Jackson.marshaller())).orElseGet(() -> complete(NOT_FOUND));
}
This doesn't compile: Bad return type in lambda expression: Route cannot be converted to RouteAdapter. The longer (and first) complete returns a RouteAdapter and the second one returns a Route. If I re-write the above function like this:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> {
if(maybeEvent.isPresent()) {
return complete(OK, maybeEvent.get(), Jackson.marshaller());
}
return complete(NOT_FOUND);
};
}
...then the compiler doesn't complain, but then it is not right way to map an Optional.
Java doesn't have fold method for Optional (not in SE8 at least), which allows passing the fallback-to value first.
I'm curious whether it is possible to write this function in respecting functional style.
Update:
As asked in the comments, these are the signatures of the complete methods from akka-http javadsl library:
def complete(status: StatusCode): Route = RouteAdapter(
D.complete(status.asScala))
and
def complete[T](status: StatusCode, value: T, marshaller: Marshaller[T, RequestEntity]) = RouteAdapter {
D.complete(ToResponseMarshallable(value)(fromToEntityMarshaller(status.asScala)(marshaller)))
}

What is return type of complete(OK, maybeEvent.get(), Jackson.marshaller())?
I assume RouteAdapter. If so cast it to Route so chain will be binded to Route not RouteAdaper and at the end will not have troubles with casting from super class to subclass.

Related

Kotlin overload on lambdas that return a value VS ones that don't. Java, Groovy works, but Kotlin doesn't

very new to Kotlin and trying to make some of my API work in Kotlin without changing API much.
I have a method, let's call it client that receives a validation function. There are two variants of Validation. One that only suppose to do a validation, and the other can also return a value. To streamline user experience, in Java, I exposed two variants of the method. And it works as expected as I believe Java distincts between void and Object (<R>).
When I use my code in Kotlin, it can't distinct between two and I need to provide an explicit cast.
To remove Java from equation, I tried to replicate the situation in Kotlin using functional interfaces:
fun interface KotlinValidator {
fun validate()
}
fun interface KotlinValidatorWithReturn {
fun validateAndReturn(): Any
}
fun client(validator: KotlinValidator) {
println("validator NO return")
validator.validate()
}
fun client(validatorAndReturn: KotlinValidatorWithReturn): Any {
println("validator WITH return")
return validatorAndReturn.validateAndReturn()
}
fun test() {
val fromValidator = client {
100
}
val fromValidatorForced = client(KotlinValidatorWithReturn {
100
})
client {
}
}
it prints
validator NO return
validator WITH return
validator NO return
Based on my googling, it seems to be not possible to make it work without an explicit cast. However I hope that I am wrong as Groovy and Java let me do it.
To provide more context, I am trying to make WebTau HTTP module work nicely with Kotlin.
In Java and Groovy version I can do:
int id = http.post("/customers", customerPayload, ((header, body) -> {
return body.get("id");
}));
http.put("/customers/" + id, changedCustomerPayload, ((header, body) -> {
body.get("firstName").should(equal("FN"));
body.get("lastName").should(equal(changedLastName));
}));
In Groovy:
def id = http.post("/customers", customerPayload) {
body.id
}
But in Kotlin:
val id: Int = http.post("/customers", customerPayload, HttpResponseValidatorWithReturn { _, body ->
body.get("id")
})
The reason I brought this example is at the moment I am reluctant to change API and rename functions to distinct between the ones that return a value and the ones that don't.
The main problem is that in Kotlin, everything returns -- they may just return Unit. There is no void.
On the other hand, this may mean there is no need to distinguish between these types, you can just have the "with return" version.

Java how to Uni.createFrom().future() and return that Uni from the enclosing method?

I am very new to Java and Mutiny.
As indicated below, my test function asks Redis for the value of key "foo" which is "bar". That is working and the Future onCompleted() gets "bar".
So far so good.
I have two issues with the Uni.createFrom().future() bit.
The compiler says: The method future(Future<? extends T>) in the type UniCreate is not applicable for the arguments (Future<Response>). I have tried the suggested fixes but ended up in a deeper hole. My Java skills are insufficient to fully grasp the meaning of the error.
How do I get "bar" into the Uni<String> returned from test()? I have tried all sorts of subscribing and CompletableFutures and cannot make anything work. I figure I need to return a function to generate the Uni but am at a loss about how to do that.
// The abbreviated setup
import io.vertx.redis.client.Redis;
private final Redis redisClient;
this.redisClient = Redis.createClient(vertx);
public Uni<String> test () {
// Ask Redis for the value of key "foo" => "bar"
Future<Response> futureResponse = this.redisClient.send(Request.cmd(Command.create("JSON.GET")).arg("foo"))
.compose(response -> {
// response == 'bar'
return Future.succeededFuture(response);
}).onComplete(res -> {
// res == 'bar'
});
// How to make the return of the Uni<String> wait for the completed futureResponse
// so it makes a Uni<String> from "bar" and returns it from the method?
Uni<String> respUni = Uni.createFrom().future(futureResponse);
return respUni;
}
Thanks. Any suggestions gratefully accepted! (And yes, I have spent many hours trying to work it out for myself) ;-)
Updated the post, because of errors.
UniCreate.future() takes a java.util.concurrent.Future of some type and returns Uni of the same type. That is, you'll have to pass a java.util.concurrent.Future<String> to get a Uni<String>.
The send method of the Redis client returns a io.vertx.core.Future<Response> which is not assignment compatible to java.util.concurrent.Future.
Fortunately, the API provides io.vertx.core.Future#toCompletionStage to convert a vertx Future to a JDK CompletionStage while Mutiny provides UniCreate.completionStage() to get the job done.
public Uni<String> test () {
Future<String> futureResponse = this.redisClient.send(Request.cmd(Command.create("JSON.GET")).arg("foo"))
.compose(response -> {
return Future.succeededFuture(response.toString());
});
Uni<String> respUni = Uni.createFrom().completionStage(futureResponse.toCompletionStage());
return respUni;
}

Break or return from java 8 map reduce in functional interface

I have a java 8 functional interface that accepts a list of validators that are applied on an object and returns the validation result. The validation results are accumulated in the reduce phase. The code as follows:
public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {
static LogicalTableValidator addAll(LogicalTableValidator... validators) {
// Need to break out of this validator stream, based on the criticality of a particular validation error
return logicalTable -> Arrays.stream(validators).map(v -> v.apply(logicalTable))
.reduce(new ValidationResult(logicalTable.getUid()), (validationResult, currentResult) -> {
validationResult.addValidationMessages(currentResult.getValidationMessages());
return validationResult;
});
}
}
This validation logic gets called from here
LogicalTableValidator logicalTableValidators = LogicalTableValidator.addAll(getValidators());
List<ValidationResult> ltValidationResults = logicalTables.stream()
.parallel()
.map(logicalTableValidators)
.collect(Collectors.toList());
The problem I am facing is that, I am not able to break from the validation logic conditionally. This will be the case when I am applying the validators on the logicalObject, if the validation fails with a critical error, I dont need to run rest of the validators. Instead I need to stop the validation process right there.
A work around would be not to use lambda expression for validation and use the following code instead.
return new LogicalTableValidator() {
#Override
public ValidationResult apply(LogicalTable t) {
ValidationResult result = new ValidationResult(t.getUid());
for (LogicalTableValidator validator : validators) {
ValidationResult currentResult = validator.apply(t);
List<ValidationMessage> messages = currentResult.getValidationMessages();
Boolean exit = false;
for (ValidationMessage message : messages) {
if(StringUtils.equalsIgnoreCase(message.getSeverity(), "1")) {
exit = true;
break;
}
}
result.addValidationMessages(currentResult.getValidationMessages());
if (exit) break;
}
return result;
}
};
It seems, not using lambda expression in functional interface, defeats the purpose of using functional interface, but I couldn't figure out a way to conditionally break out of the validation loop. Is there any alternative I can use? Should this code be structured in a different way?
You can try something like below. In peek it collect ValidationMessages. In filter and findFirst it stop after first error message. It is replacement for takeWhile that was mentioned in comments, you can also check this.
public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {
static LogicalTableValidator addAll(LogicalTableValidator... validators) {
logicalTable -> {
ValidationResult result = new ValidationResult(logicalTable.getUid());
Arrays.stream(validators).map(v -> v.apply(logicalTable))
.peek(currentResult -> result.addValidationMessages(currentResult.getValidationMessages()))
.filter(currentResult -> currentResult.getValidationMessages().stream()
.filter(message -> StringUtils.equalsIgnoreCase(message.getSeverity(), "1"))
.count() > 0)
.findFirst()
.orElse(null);
return result;
}
}
}
There are two distinct things: 1. breaking logicalTables stream and 2. breaking validators stream.
For logicalTables, your stream is parallel and even if the break was possible you would obtain potentially different results.
For validators stream, Stream.takeWhile seems to be the closest to pure stream-based solution. Unfortunately, it is in JDK since Java 9 and moreover it doesn't comprise invalid ValidationResult into resulting stream. Alternatives might exist in external libraries though the imperative code seems to me as simplest and readable enough at this moment.

Java Optional return value only if present

Is it possible to return the Optional value from method only if it's present, but if it's not just continue with a normal method flow. Something like this:
public Message processMessage(Message message) {
// ErrorMessage is subclass of Message; only returned if validator found some violations, otherwise empty optional
Optional<ErrorMessage> error = validator.validate(message);
if (error.isPresent()) return error.get();
// returns different possible subclasses of Message
return service.processMessage(message);
}
Is there any prettier way to write this?
Your problem is indeed that the return types do not match. orElseGet only works when the supplier returns a subtype of the Optional type.
To work around this, you can force a cast to the parent type first:
return error.<Message>map(m -> m).orElseGet(() -> service.processMessage(message));
or equivalently:
return error.map(m -> (Message) m).orElseGet(() -> service.processMessage(message));
I simply would go with Optional.orElseGet and an explicit cast in between:
public Message processMessage(final Message message) {
return validator.validate(message)
.map(Message.class::cast)
.orElseGet(() -> service.processMessage(message));
}
I am not able to test it currently but it may give u an idea, may be you can implement something like below
return Optional.ofNullable(message)
.map(validator::validate)
.orElseGet(service::processMessage)
Looking at that snippet, it looks like the validate method on the validator doesn't quite have the proper return type. Consider using e.g. io.vavr.control.Either or io.vavr.control.Validation monad. Take a look at a possible signature for validate:
Either<SpecificError, ? extends Message> validate(Message message);
Now the map and fold combinators can be used like so:
validator
.validate(message)
.map(message -> service.processMessage(message))
.fold(error -> new ErrorMessage(error), success -> success); // the left function can be replaced by Function.identity()
to yield Message.

Functional programming: How to carry on the context for a chain of validation rules

I have a set of functions (rules) for validation which take a context as parameter and either return "Okay" or an "Error" with a message. Basically these could return a Maybe (Haskell) / Optional (Java) type.
In the following I would like to validate properties of a Fruit (the context) and return an error message if the validation failed, otherwise "Okay"/Nothing.
Note:
I would prefer a solution that is purely functional style and stateless/immutable. It is a bit of a Kata, actually.
For my experiments I used Kotlin, but the core problem also applies to any language that supports higher order functions (such as Java and Haskell).
You can find a link to the full source code here and the same at the very bottom.
Given a Fruit class with color and weight, plus some example rules:
data class Fruit(val color:String, val weight:Int)
fun theFruitIsRed(fruit: Fruit) : Optional<String> =
if (fruit.color == "red") Optional.empty() else Optional.of("Fruit not red")
fun fruitNotTooHeavy(fruit: Fruit) : Optional<String> =
if (fruit.weight < 500) Optional.empty() else Optional.of("Too heavy")
Now I would like to chain the rule evaluation using a reference to the respective function, without specifying the context as an argument using a FruitRuleProcessor.
When processing a rule fails, it should not evaluate any of the other rules.
For Example:
fun checkRules(fruit:Fruit) {
var res = FruitRuleProcessor(fruit).check(::theFruitIsNotRed).check(::notAnApple).getResult()
if (!res.isEmpty()) println(res.get())
}
def main(args:Array<String) {
// "Fruit not red": The fruit has the wrong color and the weight check is thus skipped
checkRules(Fruit("green","200"))
// Prints "Fruit too heavy": Color is correct, checked weight (too heavy)
checkRules(Fruit("red","1000"))
}
I do not care where it failed, only about the result. Also when a function returns an error, the others should not be processed.
Again, this pretty much sounds like an Optional Monad.
Now the problem is that somehow I have to carry the fruit context from check to check call.
One solution I tried is to implement a Result class that takes a context as value and has two subclasses RuleError(context:Fruit, message:String) and Okay(context). The difference to Optional is that now I can wrap around the Fruit context (think T = Fruit)
// T: Type of the context. I tried to generify this a bit.
sealed class Result<T>(private val context:T) {
fun isError () = this is RuleError
fun isOkay() = this is Okay
// bind
infix fun check(f: (T) -> Result<T>) : Result<T> {
return if (isError()) this else f(context)
}
class RuleError<T>(context: T, val message: String) : Result<T>(context)
class Okay<T>(context: T) : Result<T>(context)
}
I think that this looks like a monoid/Monad, with return in the constructor lifting a Fruit into a Result and or being the bind. Although I tried some Scala and Haskell, admittedly I am not so experienced with that.
Now we can change the rules to
fun theFruitIsNotTooHeavy(fruit: Fruit) : Result<Fruit> =
if (fruit.weight < 500) Result.Okay(fruit) else Result.RuleError(fruit, "Too heavy")
fun theFruitIsRed(fruit: Fruit) : Result<Fruit> =
if (fruit.color == "red") Result.Okay(fruit) else Result.RuleError(fruit, "Fruit not red")
which allows to chain checks like intended:
fun checkRules(fruit:Fruit) {
val res = Result.Okay(fruit).check(::theFruitIsRed).check(::theFruitIsNotTooHeavy)
if (res.isError()) println((res as Result.RuleError).message)
}
// Prints:
Fruit not red
Too heavy
However this has one major drawback: The Fruit context now becomes part of the validation result, although it is not strictly necessary in there.
So to wrap it up: I'm looking for a way
to carry the fruit context when invoking the functions
so that I can chain (basically: compose) multiple checks in a row using the the same method
along with the results of the rule functions without changing the interface of these.
without side-effects
What functional programming patterns could solve this problem? Is it Monads as my gut feeling tries to tell me that?
I would prefer a solution that can be done in Kotlin or Java 8 (for bonus points), but answers in other languages (e.g. Scala or Haskell) also could be helpful. (It's about the concept, not the language :) )
You can find the full source code from this question in this fiddle.
You could use/create a monoid wrapper of your Optional/Maybe type such as First in Haskell which combines values by returning the first non-Nothing value.
I don't know Kotlin, but in Haskell it would look like this:
import Data.Foldable (foldMap)
import Data.Monoid (First(First, getFirst))
data Fruit = Fruit { color :: String, weight :: Int }
theFruitIsRed :: Fruit -> Maybe String
theFruitIsRed (Fruit "red" _) = Nothing
theFruitIsRed _ = Just "Fruit not red"
theFruitIsNotTooHeavy :: Fruit -> Maybe String
theFruitIsNotTooHeavy (Fruit _ w)
| w < 500 = Nothing
| otherwise = Just "Too heavy"
checkRules :: Fruit -> Maybe String
checkRules = getFirst . foldMap (First .)
[ theFruitIsRed
, theFruitIsNotTooHeavy
]
Ideone Demo
Note that I'm taking advantage of the Monoid instance of functions here:
Monoid b => Monoid (a -> b)
Since the type of the object being validated can't change (as the object itself shouldn't change), I wouldn't use a monad (or any sort of functor). I'd have a type Validator a err = a -> [err]. If a validator succeeds, it outputs [] (no error). This forms a monoid, where mzero = const [] and mappend f g x = f x `mappend` g x. Haskell has this built in as instance Monoid b => Monoid (a -> b)
EDIT: I appear to have misread the question. #4castle's answer is almost exactly this one but uses Maybe err instead of [err]. Use that.
// Scala, because I'm familiar with it, but it should translate to Kotlin
case class Validator[-A, +Err](check: A => Seq[Err]) {
def apply(a: A): Err = check(a)
def |+|[AA >: A](that: Validator[A, Err]): Validator[AA, Err]
= Validator { a =>
this(a) ++ that(a)
}
}
object Validator {
def success[A, E]: Validator[A, E] = Validator { _ => Seq() }
}
type FruitValidator = Validator[Fruit, String]
val notTooHeavy: FruitValidator = Validator { fruit =>
if(fruit.weight < 500) Seq() else Seq("Too heavy")
// Maybe make a helper method for this logic
}
val isRed: FruitValidator = Validator { fruit =>
if (fruit.color == "red") Seq() else Seq("Not red")
}
val compositeRule: FruitValidator = notTooHeavy |+| isRed
To use, just call a Validator like compositeRule(Fruit("green", 700)), which returns 2 errors in this case.
To see why the reader monad is inappropriate here, consider what happens if
type Validator = ReaderT Fruit (Either String) Fruit
ruleA :: Validator
ruleA = ReaderT $ \fruit ->
if color fruit /= "red" then Left "Not red"
else Right fruit
ruleB :: Validator
ruleB = ReaderT $ \fruit ->
if weight fruit >= 500 then Left "Too heavy"
else Right fruit
ruleC = ruleA >> ruleB
greenHeavy = Fruit "green" 700
Both ruleA and ruleB fail for greenHeavy, yet running runReaderT ruleC greenHeavy only produces the first error. This is undesirable: you likely want as many errors as possible revealed per run.
Also, you can "hijack" the validation:
bogusRule :: ReaderT Fruit (Either String) Int
bogusRule = return 42
ruleD = do ruleA
ruleB
bogusRule -- Validates just fine... then throws away the Fruit so you can't validate further.
There are couple of Haskell implementations,
so let's try to solve it with Kotlin.
First, we start with the Data-Object:
class Fruit(val color: String, val weight: Int)
And we need a Type that represents a Fruit and whether an error occurred:
sealed class Result<out E, out O> {
data class Error<E>(val e: E) : Result<E, Nothing>()
data class Ok<O>(val o: O): Result<Nothing, O>()
}
Now lets define the Type of a FruitRule:
typealias FruitRule = (Fruit) -> String?
The FruitRule is a function that receives a Fruit-Instance
and returns null if the rule passed or the error message.
The problem we got here is that FruitRule itself is not composable.
So we need a Type that is composable and runs a FruitRule on a Fruit
typealias ComposableFruitRule = (Result<String, Fruit>) -> Result<String, Fruit>
First, we need a way to create a ComposableFruitRule from a FruitRule
fun createComposableRule(f: FruitRule): ComposableFruitRule {
return { result: Result<String, Fruit> ->
if(result is Result.Ok<Fruit>) {
val temporaryResult = f(result.o)
if(temporaryResult is String)
Result.Error(temporaryResult)
else
//We know that the rule passed,
//so we can return Result.Ok<Fruit> we received back
result
} else {
result
}
}
}
createComposableFruitRule returns a lambda that first checks whether the provided Result is Result.Ok. If yes, it runs the provided FruitRule on the given Fruit and returns Result.Error if the error message is not null.
Now lets make our ComposableFruitRule composable:
infix fun ComposableFruitRule.composeRules(f: FruitRule): ComposableFruitRule {
return { result: Result<String, Fruit> ->
val temporaryResult = this(result)
if(temporaryResult is Result.Ok<Fruit>) {
createComposableRule(f)(temporaryResult)
} else {
temporaryResult
}
}
}
This infix-function composes a ComposableFruitRule together with a FruitRule, that means first the internal FruitRule is invoked. If there is no error, the FruitRule provided as a parameter is invoked.
So now we are able to compose FruitRules together and afterward just provide a Fruit and check the rules.
fun colorIsRed(fruit: Fruit): String? {
return if(fruit.color == "red")
null
else
"Color is not red"
}
fun notTooHeavy(fruit: Fruit): String? {
return if(fruit.weight < 500)
null
else
"Fruit too heavy"
}
fun main(args: Array<String>) {
val ruleChecker = createComposableRule(::colorIsRed) composeRules ::notTooHeavy
//We can compose as many rules as we want
//e.g. ruleChecker composeRules ::fruitTooOld composeRules ::fruitNotTooLight
val fruit1 = Fruit("blue", 300)
val result1 = ruleChecker(Result.Ok(fruit1))
println(result1)
val fruit2 = Fruit("red", 700)
val result2 = ruleChecker(Result.Ok(fruit2))
println(result2)
val fruit3 = Fruit("red", 350)
val result3 = ruleChecker(Result.Ok(fruit3))
println(result3)
}
The Output of that main is:
Error(e=Color is not red)
Error(e=Fruit too heavy)
Ok(o=Fruit#65b54208)
To answer generally the question
Now the problem is that somehow I have to carry the fruit context from check to check call.
...phrased as...
Given some monad M, how do I chain some M actions while also (implicitly) giving the same “context” object to each?
The Haskell answer would be to use the ReaderT monad transformer. It takes any monad, such as Maybe, and gives you another monad which implicitly passes a “global constant” to each action.
Let me rewrite your checkers in Haskell:
data Fruit = Fruit {colour::String, weight::Int}
theFruitIsRed :: Fruit -> Either String ()
theFruitIsRed fruit
| colour fruit == "red" = Right ()
| otherwise = Left "Fruit not red"
fruitNotTooHeavy :: Fruit -> Either String ()
fruitNotTooHeavy fruit
| weight fruit < 500 = Right ()
| otherwise = Left "Too heavy"
Note that I've used Either String () instead of Maybe String because I want String to be the “abort case”, whereas in the Maybe monad it would be the “carry on” case.
Now, instead of doing
checks :: Fruit -> Either String ()
checks fruit = do
theFruitIsRed fruit
fruitNotTooHeavy fruit
I can do
checks = runReaderT $ do
ReaderT theFruitIsRed
ReaderT fruitNotTooHeavy
Your Result class seems to be essentially a special instantiation of the ReaderT transformer. Not sure if you could implement the exact thing in Kotlin as well.
It sounds like you are looking for an error monad. Its like the Maybe (aka Option) monad, but the error case carries a message.
In Haskell its just the Either type, with the first argument being the type of the error value.
type MyError a = Either String a
If you check the Data.Either documentation you will see that Either e is already an instance of Monad, so you don't need to do anything else. You can just write:
notTooHeavy :: Fruit -> MyError ()
notTooHeavy fruit =
when (weight fruit > 500) $ fail "Too heavy"
What the monad instance does is stop the computation at the first fail, so you get e.g. Left "Too heavy" or Right (). If you want to accumulate errors then you have to do somthing more complicated.
Other posters have suggested that you don't need monads because your example code has all the functions returning (). While this may be true of your examples, I'm reluctant to generalise that fast. Also since you get the monadic instance automatically with Either it makes sense to just use it.
Is it Monads as my gut feeling tries to tell me that?
I think Monad is too strong a requirement in your case. Your validation functions
fun theFruitIsRed(fruit: Fruit) : Optional< String>
don't return an useable value when they validate successfully. And a defining characteristic of Monad is being able do decide what future computations to execute based on a previous result. "If the first validator succeeds returning foo, validate this field, if it succeeds returning bar, validate this other field instead".
I'm not knowledgeable about Kotlin, but I think you could have a Validator<T> class. It basically would wrap a single validation function for a type T that returned an Optional<String>.
Then you could write a method that combined two validators into a composite validator. The inner function of the composite validator would receive a T, run the first validator, return the error if it fails, if not run the second validator. (If your validators returned some useful result on successful validation, like say non-fatal warnings, you would need to supply an additional function to combine these results.)
The idea its that you would first compose the validators, and only then supply the actual T to get the final result. This compose-before-running approach is used by Java's Comparator, for example.
Notice that in this solution, even if your functions returned some result on successful validation, those values would not be used to select what validations to do next (though an error would stop the chain). You could combine results using a function but that's it. This "more rigid" style of programming is called Applicative in Haskell. All types supporting a Monad interface can be used in an Applicative way, but some types support Applicative without supporting Monad.
Another interesting aspect of validators is that they are contravariant on their input type T. This means that you can "pre-apply" a function from A to B to a Validator<B>, resulting in a Validator<A> whose type went "backwards" compared to the direction of the function. (The mapping function of Java's Collectors class works this way.)
And you can go further down this route by having functions that build a validator for a composite out of validators for their individual parts. (What in Haskell is called Divisible.)

Categories