Arrow in Kotlin
Issue: BAEL-1495
This commit is contained in:
		
							parent
							
								
									4d30ff3b43
								
							
						
					
					
						commit
						2c4cefe516
					
				| @ -87,6 +87,13 @@ | ||||
|             <artifactId>h2</artifactId> | ||||
|             <version>${h2database.version}</version> | ||||
|         </dependency> | ||||
|         <!-- https://mvnrepository.com/artifact/io.arrow-kt/arrow-core --> | ||||
|         <dependency> | ||||
|             <groupId>io.arrow-kt</groupId> | ||||
|             <artifactId>arrow-core</artifactId> | ||||
|             <version>0.7.3</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|  | ||||
| @ -0,0 +1,54 @@ | ||||
| package com.baeldung.kotlin.arrow | ||||
| 
 | ||||
| import arrow.core.Either | ||||
| import arrow.core.filterOrElse | ||||
| import kotlin.math.sqrt | ||||
| 
 | ||||
| class FunctionalErrorHandlingWithEither { | ||||
| 
 | ||||
|     sealed class ComputeProblem { | ||||
|         object OddNumber : ComputeProblem() | ||||
|         object NotANumber : ComputeProblem() | ||||
|     } | ||||
| 
 | ||||
|     fun parseInput(s : String) : Either<ComputeProblem, Int> = Either.cond(s.toIntOrNull() != null, {-> s.toInt()}, {->ComputeProblem.NotANumber} ) | ||||
| 
 | ||||
|     fun isEven(x : Int) : Boolean = x % 2 == 0 | ||||
| 
 | ||||
|     fun biggestDivisor(x: Int) : Int = biggestDivisor(x, 2) | ||||
| 
 | ||||
|     fun biggestDivisor(x : Int, y : Int) : Int { | ||||
|         if(x == y){ | ||||
|             return 1; | ||||
|         } | ||||
|         if(x % y == 0){ | ||||
|             return x / y; | ||||
|         } | ||||
|         return biggestDivisor(x, y+1) | ||||
|     } | ||||
| 
 | ||||
|     fun isSquareNumber(x : Int) : Boolean { | ||||
|         val sqrt: Double = sqrt(x.toDouble()) | ||||
|         return sqrt % 1.0 == 0.0 | ||||
|     } | ||||
| 
 | ||||
|     fun computeWithEither(input : String) : Either<ComputeProblem, Boolean> { | ||||
|         return parseInput(input) | ||||
|                 .filterOrElse(::isEven) {->ComputeProblem.OddNumber} | ||||
|                 .map (::biggestDivisor) | ||||
|                 .map (::isSquareNumber) | ||||
|     } | ||||
| 
 | ||||
|     fun computeWithEitherClient(input : String) { | ||||
|         val computeWithEither = computeWithEither(input) | ||||
| 
 | ||||
|         when(computeWithEither){ | ||||
|             is Either.Right -> "The greatest divisor is square number: ${computeWithEither.b}" | ||||
|             is Either.Left -> when(computeWithEither.a){ | ||||
|                 is ComputeProblem.NotANumber -> "Wrong input! Not a number!" | ||||
|                 is ComputeProblem.OddNumber -> "It is an odd number!" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| package com.baeldung.kotlin.arrow | ||||
| 
 | ||||
| import arrow.core.None | ||||
| import arrow.core.Option | ||||
| import arrow.core.Some | ||||
| import kotlin.math.sqrt | ||||
| 
 | ||||
| class FunctionalErrorHandlingWithOption { | ||||
| 
 | ||||
|     fun parseInput(s : String) : Option<Int> = Option.fromNullable(s.toIntOrNull()) | ||||
| 
 | ||||
|     fun isEven(x : Int) : Boolean = x % 2 == 0 | ||||
| 
 | ||||
|     fun biggestDivisor(x: Int) : Int = biggestDivisor(x, 2) | ||||
| 
 | ||||
|     fun biggestDivisor(x : Int, y : Int) : Int { | ||||
|         if(x == y){ | ||||
|             return 1; | ||||
|         } | ||||
|         if(x % y == 0){ | ||||
|             return x / y; | ||||
|         } | ||||
|         return biggestDivisor(x, y+1) | ||||
|     } | ||||
| 
 | ||||
|     fun isSquareNumber(x : Int) : Boolean { | ||||
|         val sqrt: Double = sqrt(x.toDouble()) | ||||
|         return sqrt % 1.0 == 0.0 | ||||
|     } | ||||
| 
 | ||||
|     fun computeWithOption(input : String) : Option<Boolean> { | ||||
|         return parseInput(input) | ||||
|                 .filter(::isEven) | ||||
|                 .map(::biggestDivisor) | ||||
|                 .map(::isSquareNumber) | ||||
|     } | ||||
| 
 | ||||
|     fun computeWithOptionClient(input : String) : String{ | ||||
|         val computeOption = computeWithOption(input) | ||||
| 
 | ||||
|         return when(computeOption){ | ||||
|             is None -> "Not an even number!" | ||||
|             is Some -> "The greatest divisor is square number: ${computeOption.t}" | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,143 @@ | ||||
| package com.baeldung.kotlin.arrow | ||||
| 
 | ||||
| import arrow.core.* | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalDataTypes { | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenIdCreated_thanValueIsPresent(){ | ||||
|         val id = Id("foo") | ||||
|         val justId = Id.just("foo"); | ||||
| 
 | ||||
|         Assert.assertEquals("foo", id.extract()) | ||||
|         Assert.assertEquals(justId, id) | ||||
|     } | ||||
| 
 | ||||
|     fun length(s : String) : Int = s.length | ||||
| 
 | ||||
|     fun isBigEnough(i : Int) : Boolean = i > 10 | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenIdCreated_thanMapIsAssociative(){ | ||||
|         val foo = Id("foo") | ||||
| 
 | ||||
|         val map1 = foo.map(::length) | ||||
|                 .map(::isBigEnough) | ||||
|         val map2 = foo.map { s -> isBigEnough(length(s)) } | ||||
| 
 | ||||
|         Assert.assertEquals(map1, map2) | ||||
|     } | ||||
| 
 | ||||
|     fun lengthId(s : String) : Id<Int> = Id.just(length(s)) | ||||
| 
 | ||||
|     fun isBigEnoughId(i : Int) : Id<Boolean> = Id.just(isBigEnough(i)) | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenIdCreated_thanFlatMapIsAssociative(){ | ||||
|         val bar = Id("bar") | ||||
| 
 | ||||
|         val flatMap = bar.flatMap(::lengthId) | ||||
|             .flatMap(::isBigEnoughId) | ||||
|         val flatMap1 = bar.flatMap { s -> lengthId(s).flatMap(::isBigEnoughId) } | ||||
| 
 | ||||
|         Assert.assertEquals(flatMap, flatMap1) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenOptionCreated_thanValueIsPresent(){ | ||||
|         val factory = Option.just(42) | ||||
|         val constructor = Option(42) | ||||
|         val emptyOptional = Option.empty<Integer>() | ||||
|         val fromNullable = Option.fromNullable(null) | ||||
| 
 | ||||
|         Assert.assertEquals(42, factory.getOrElse { -1 }) | ||||
|         Assert.assertEquals(factory, constructor) | ||||
|         Assert.assertEquals(emptyOptional, fromNullable) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenOptionCreated_thanConstructorDifferFromFactory(){ | ||||
|         val constructor : Option<String?> = Option(null) | ||||
|         val fromNullable : Option<String?> = Option.fromNullable(null) | ||||
| 
 | ||||
|         try{ | ||||
|             constructor.map { s -> s!!.length } | ||||
|             Assert.fail() | ||||
|         } catch (e : KotlinNullPointerException){ | ||||
|             fromNullable.map { s->s!!.length } | ||||
|         } | ||||
|         Assert.assertNotEquals(constructor, fromNullable) | ||||
|     } | ||||
| 
 | ||||
|     fun wrapper(x : Integer?) : Option<Int> = if (x == null) Option.just(-1) else Option.just(x.toInt()) | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenOptionFromNullableCreated_thanItBreaksLeftIdentity(){ | ||||
|         val optionFromNull = Option.fromNullable(null) | ||||
| 
 | ||||
|         Assert.assertNotEquals(optionFromNull.flatMap(::wrapper), wrapper(null)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenEitherCreated_thanOneValueIsPresent(){ | ||||
|         val rightOnly : Either<String,Int> = Either.right(42) | ||||
|         val leftOnly : Either<String,Int> = Either.left("foo") | ||||
| 
 | ||||
|         Assert.assertTrue(rightOnly.isRight()) | ||||
|         Assert.assertTrue(leftOnly.isLeft()) | ||||
|         Assert.assertEquals(42, rightOnly.getOrElse { -1 }) | ||||
|         Assert.assertEquals(-1, leftOnly.getOrElse { -1 }) | ||||
| 
 | ||||
|         Assert.assertEquals(0, rightOnly.map { it % 2 }.getOrElse { -1 }) | ||||
|         Assert.assertEquals(-1, leftOnly.map { it % 2 }.getOrElse { -1 }) | ||||
|         Assert.assertTrue(rightOnly.flatMap { Either.Right(it % 2) }.isRight()) | ||||
|         Assert.assertTrue(leftOnly.flatMap { Either.Right(it % 2) }.isLeft()) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenEvalNowUsed_thenMapEvaluatedLazily(){ | ||||
|         val now = Eval.now(1) | ||||
|         Assert.assertEquals(1, now.value()) | ||||
| 
 | ||||
|         var counter : Int = 0 | ||||
|         val map = now.map { x -> counter++; x+1 } | ||||
|         Assert.assertEquals(0, counter) | ||||
|          | ||||
|         val value = map.value() | ||||
|         Assert.assertEquals(2, value) | ||||
|         Assert.assertEquals(1, counter) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenEvalLaterUsed_theResultIsMemoized(){ | ||||
|         var counter : Int = 0 | ||||
|         val later = Eval.later { counter++; counter } | ||||
|         Assert.assertEquals(0, counter) | ||||
| 
 | ||||
|         val firstValue = later.value() | ||||
|         Assert.assertEquals(1, firstValue) | ||||
|         Assert.assertEquals(1, counter) | ||||
| 
 | ||||
|         val secondValue = later.value() | ||||
|         Assert.assertEquals(1, secondValue) | ||||
|         Assert.assertEquals(1, counter) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun whenEvalAlwaysUsed_theResultIsNotMemoized(){ | ||||
|         var counter : Int = 0 | ||||
|         val later = Eval.always { counter++; counter } | ||||
|         Assert.assertEquals(0, counter) | ||||
| 
 | ||||
|         val firstValue = later.value() | ||||
|         Assert.assertEquals(1, firstValue) | ||||
|         Assert.assertEquals(1, counter) | ||||
| 
 | ||||
|         val secondValue = later.value() | ||||
|         Assert.assertEquals(2, secondValue) | ||||
|         Assert.assertEquals(2, counter) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,68 @@ | ||||
| package com.baeldung.kotlin.arrow | ||||
| 
 | ||||
| import arrow.core.Either | ||||
| import com.baeldung.kotlin.arrow.FunctionalErrorHandlingWithEither.ComputeProblem.NotANumber | ||||
| import com.baeldung.kotlin.arrow.FunctionalErrorHandlingWithEither.ComputeProblem.OddNumber | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalErrorHandlingWithEitherTest { | ||||
| 
 | ||||
|     val operator = FunctionalErrorHandlingWithEither() | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenInvalidInput_whenComputeInvoked_NotANumberIsPresent(){ | ||||
|         val computeWithEither = operator.computeWithEither("bar") | ||||
| 
 | ||||
|         Assert.assertTrue(computeWithEither.isLeft()) | ||||
|         when(computeWithEither){ | ||||
|             is Either.Left -> when(computeWithEither.a){ | ||||
|                 NotANumber -> "Ok." | ||||
|                 else -> Assert.fail() | ||||
|             } | ||||
|             else -> Assert.fail() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenOddNumberInput_whenComputeInvoked_OddNumberIsPresent(){ | ||||
|         val computeWithEither = operator.computeWithEither("121") | ||||
| 
 | ||||
|         Assert.assertTrue(computeWithEither.isLeft()) | ||||
|         when(computeWithEither){ | ||||
|             is Either.Left -> when(computeWithEither.a){ | ||||
|                 OddNumber -> "Ok." | ||||
|                 else -> Assert.fail() | ||||
|             } | ||||
|             else -> Assert.fail() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenEvenNumberWithoutSquare_whenComputeInvoked_OddNumberIsPresent(){ | ||||
|         val computeWithEither = operator.computeWithEither("100") | ||||
| 
 | ||||
|         Assert.assertTrue(computeWithEither.isRight()) | ||||
|         when(computeWithEither){ | ||||
|             is Either.Right -> when(computeWithEither.b){ | ||||
|                 false -> "Ok." | ||||
|                 else -> Assert.fail() | ||||
|             } | ||||
|             else -> Assert.fail() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenEvenNumberWithSquare_whenComputeInvoked_OddNumberIsPresent(){ | ||||
|         val computeWithEither = operator.computeWithEither("98") | ||||
| 
 | ||||
|         Assert.assertTrue(computeWithEither.isRight()) | ||||
|         when(computeWithEither){ | ||||
|             is Either.Right -> when(computeWithEither.b){ | ||||
|                 true -> "Ok." | ||||
|                 else -> Assert.fail() | ||||
|             } | ||||
|             else -> Assert.fail() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| package com.baeldung.kotlin.arrow | ||||
| 
 | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalErrorHandlingWithOptionTest { | ||||
| 
 | ||||
|     val operator = FunctionalErrorHandlingWithOption() | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenInvalidInput_thenErrorMessageIsPresent(){ | ||||
|         val useComputeOption = operator.computeWithOptionClient("foo") | ||||
|         Assert.assertEquals("Not an even number!", useComputeOption) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenOddNumberInput_thenErrorMessageIsPresent(){ | ||||
|         val useComputeOption = operator.computeWithOptionClient("539") | ||||
|         Assert.assertEquals("Not an even number!",useComputeOption) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenEvenNumberInputWithNonSquareNum_thenFalseMessageIsPresent(){ | ||||
|         val useComputeOption = operator.computeWithOptionClient("100") | ||||
|         Assert.assertEquals("The greatest divisor is square number: false",useComputeOption) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun givenEvenNumberInputWithSquareNum_thenTrueMessageIsPresent(){ | ||||
|         val useComputeOption = operator.computeWithOptionClient("242") | ||||
|         Assert.assertEquals("The greatest divisor is square number: true",useComputeOption) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user