Added functor map method and unit tests

This commit is contained in:
Marco Cetica 2024-09-17 16:23:43 +02:00
parent 43ce72e819
commit 7ebc811d0e
Signed by: marco
GPG Key ID: 45060A949E90D0FD
5 changed files with 60 additions and 5 deletions

View File

@ -15,7 +15,8 @@ import java.util.function.Function;
public sealed interface Either<L, R> permits Left, Right {
/**
* <p>
* Executing an anonymous function by discriminating the Either data type value
* Executing an anonymous function by discriminating against
* the <i>Either</i> data type value
* </p>
*
* @param onLeft The function to execute on the Left case
@ -27,7 +28,7 @@ public sealed interface Either<L, R> permits Left, Right {
/**
* <p>
* Returns true if the Either type is instantiated with the Left subtype,
* Returns true if the <i>Either</i> type is instantiated with the Left subtype,
* false otherwise
* </p>
* @return Boolean value
@ -36,10 +37,30 @@ public sealed interface Either<L, R> permits Left, Right {
/**
* <p>
* Returns true if the Either type is instantiated with the Right subtype,
* Returns true if the Either type is instantiated with the <i>Right</i> subtype,
* false otherwise
* </p>
* @return Boolean value
*/
boolean isRight();
/**
* <p>
* Defines a functor. That is, a data type that supports
* a mapping operation defined by the map method.
* <br /><br />
* This method
* applies a function(<i>fn</i>) to the values inside the data type,
* returning a new data type(i.e., a new functor) if and only if the the Either
* type is instantiated with the <i>Right</i> subtype. Otherwise it leaves the functor
* unchanged.
* <br /><br />
* The type of the resulting functor is the return type specified on the <i>fn</i>
* function
* </p>
* @param fn The function to applies to the Either data type
* @return An <i>Either</i> functor
* @param <T> The return type of the <i>fn</i> function
*/
<T> Either<L, T> map(Function<R, T> fn);
}

View File

@ -26,4 +26,9 @@ public record Left<L, R>(L value) implements Either<L, R> {
public boolean isRight() {
return false;
}
@Override
public <T> Either<L, T> map(Function<R, T> fn) {
return new Left<>(this.value);
}
}

View File

@ -26,4 +26,9 @@ public record Right<L, R>(R value) implements Either<L, R> {
public boolean isRight() {
return true;
}
@Override
public <T> Either<L, T> map(Function<R, T> fn) {
return new Right<>(fn.apply(this.value));
}
}

View File

@ -9,10 +9,12 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
public class LeftTests {
private Either<Integer, String> resEither;
private Either<Error, Integer> numEither;
@BeforeEach
public void tearUp() {
this.resEither = new Left<>(19);
this.numEither = new Left<>(new Error("Undefined variable"));
}
@Test
@ -36,4 +38,14 @@ public class LeftTests {
public void testIsRight() {
assertFalse(this.resEither.isRight());
}
@Test
public void testFunctorMapLeft() {
Either<Error, Integer> res = this.numEither.map(x -> x * x);
assertEquals(res.match(
Throwable::getMessage,
_ -> "Undefined variable"
), "Undefined variable");
}
}

View File

@ -9,17 +9,19 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
public class RightTests {
private Either<Integer, String> resEither;
private Either<Error, Integer> numEither;
@BeforeEach
public void tearUp() {
this.resEither = new Right<>("Query executed successfully");
this.numEither = new Right<>(4);
}
@Test
public void testMatchRight() {
var actual = this.resEither.match(
errorCode -> "Error code: " + errorCode.toString(),
successMsg -> successMsg
errorCode -> "Error code: " + errorCode.toString(),
successMsg -> successMsg
);
var expected = "Query executed successfully";
@ -36,4 +38,14 @@ public class RightTests {
public void testIsRight() {
assertTrue(this.resEither.isRight());
}
@Test
public void testFunctorMapRight() {
Either<Error, Integer> res = this.numEither.map(x -> x * x);
assertEquals((int)res.match(
_ -> 0,
x -> x
), 16);
}
}