From e48f8075d315018e3d5cd6dbe3f6594c4a23e3e0 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Fri, 24 Jul 2020 08:01:46 -0500 Subject: [PATCH 01/14] add tests for filterMap and filterNullMap --- .../src/main/kotlin/arrow/core/ListK.kt | 4 ++++ .../src/test/kotlin/arrow/core/ListKTest.kt | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index f262102a1..78d51ed1c 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -167,9 +167,13 @@ data class ListK(private val list: List) : ListKOf, List by list } } + @Deprecated("Deprecated, use filterNullMap(f: (A) -> B?) instead", ReplaceWith("filterNullMap(f: (A) -> B?)")) fun filterMap(f: (A) -> Option): ListK = flatMap { a -> f(a).fold({ empty() }, { just(it) }) } + fun filterNullMap(f: (A) -> B?): ListK = + flatMap { a -> mapN(f(a)) { just(it) } ?: empty() } + override fun hashCode(): Int = list.hashCode() /** diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 7e360c21e..6aa9232b7 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -186,6 +186,28 @@ class ListKTest : UnitSpec() { result.map { it.a }.equalUnderTheLaw(a, ListK.eq(Int.eq())) } } + + "filterMap() should map list and filter out None values" { + forAll(Gen.listK(Gen.int())) { listk -> + listk.filterMap { + when (it % 2 == 0) { + true -> it.toString().toOption() + else -> None + } + } == listk.toList().filter { it % 2 == 0 }.map { it.toString() }.k() + } + } + + "filterNullMap() should map list and filter out null values" { + forAll(Gen.listK(Gen.int())) { listk -> + listk.filterNullMap { + when (it % 2 == 0) { + true -> it.toString() + else -> null + } + } == listk.toList().filter { it % 2 == 0 }.map { it.toString() }.k() + } + } } private fun bijection(from: Kind, Int>>): ListK>> = From 44a19b8e65c52db7278cfb945234a25105c65e28 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Fri, 24 Jul 2020 08:43:04 -0500 Subject: [PATCH 02/14] add docs for filterNullMap --- .../src/main/kotlin/arrow/core/ListK.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index 78d51ed1c..a646104de 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -1,6 +1,7 @@ package arrow.core import arrow.Kind +import arrow.core.Ior.* import arrow.higherkind import arrow.typeclasses.Applicative import arrow.typeclasses.Show @@ -171,6 +172,21 @@ data class ListK(private val list: List) : ListKOf, List by list fun filterMap(f: (A) -> Option): ListK = flatMap { a -> f(a).fold({ empty() }, { just(it) }) } + /** + * Returns a [ListK] containing the transformed values from the original + * [ListK] as long as they are non-null. + * + * Example: + * ```kotlin:ank:playground + * import arrow.core.* + * listOf(1, 2).k().filterNullMap { + * when (it % 2 == 0) { + * true -> it.toString() + * else -> null + * } + * } // Result: listOf("2").k() + * ``` + */ fun filterNullMap(f: (A) -> B?): ListK = flatMap { a -> mapN(f(a)) { just(it) } ?: empty() } From 4923f99c297bd3933a920f91dfe095a426251158 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Tue, 28 Jul 2020 21:34:14 -0500 Subject: [PATCH 03/14] passing test for padZip --- .../src/main/kotlin/arrow/core/ListK.kt | 42 ++++++++++++++++++- .../src/test/kotlin/arrow/core/ListKTest.kt | 12 ++++++ settings.gradle | 3 ++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index a646104de..52a9a4070 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -1,7 +1,6 @@ package arrow.core import arrow.Kind -import arrow.core.Ior.* import arrow.higherkind import arrow.typeclasses.Applicative import arrow.typeclasses.Show @@ -179,12 +178,19 @@ data class ListK(private val list: List) : ListKOf, List by list * Example: * ```kotlin:ank:playground * import arrow.core.* - * listOf(1, 2).k().filterNullMap { + * + * //sampleStart + * val evenStrings = listOf(1, 2).k().filterNullMap { * when (it % 2 == 0) { * true -> it.toString() * else -> null * } * } // Result: listOf("2").k() + * //sampleEnd + * + * fun main() { + * println("evenStrings = $evenStrings") + * } * ``` */ fun filterNullMap(f: (A) -> B?): ListK = @@ -205,6 +211,38 @@ data class ListK(private val list: List) : ListKOf, List by list { a, b -> a.some() toT b.some() }) } + /** + * Returns a [ListK] containing the transformed values from the original + * [ListK] as long as they are non-null. + * + * Example: + * ```kotlin:ank:playground + * import arrow.core.* + * + * //sampleStart + * val evenStrings = listOf(1, 2).k().filterNullMap { + * when (it % 2 == 0) { + * true -> it.toString() + * else -> null + * } + * } // Result: listOf("2").k() + * //sampleEnd + * + * fun main() { + * println("evenStrings = $evenStrings") + * } + * ``` + */ +// fun padZipWithNull( +// other: ListK +// ): ListK> = +// alignWith(this, other) { ior -> +// ior.fold( +// { it.some() toT Option.empty() }, +// { Option.empty() toT it.some() }, +// { a, b -> a.some() toT b.some() }) +// } + /** * Align two Lists as in zipWith, but filling in blanks with None. */ diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 6aa9232b7..46b2ec539 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -3,6 +3,7 @@ package arrow.core import arrow.Kind import arrow.core.extensions.eq import arrow.core.extensions.hash +import arrow.core.extensions.list.zip.zipWith import arrow.core.extensions.listk.align.align import arrow.core.extensions.listk.applicative.applicative import arrow.core.extensions.listk.crosswalk.crosswalk @@ -23,6 +24,8 @@ import arrow.core.extensions.listk.show.show import arrow.core.extensions.listk.traverse.traverse import arrow.core.extensions.listk.unalign.unalign import arrow.core.extensions.listk.unzip.unzip +import arrow.core.extensions.listk.zip.zipWith +import arrow.core.extensions.option.eq.eq import arrow.core.extensions.show import arrow.core.test.UnitSpec import arrow.core.test.generators.genK @@ -187,6 +190,15 @@ class ListKTest : UnitSpec() { } } + "padZip" { + forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> + val left = a.map { Some(it) }.k() + List(max(0, b.count() - a.count())) { None }.k() + val right = b.map { Some(it) }.k() + List(max(0, a.count() - b.count())) { None }.k() + + a.padZip(b) == left.zipWith(right) { l, r -> l toT r } + } + } + "filterMap() should map list and filter out None values" { forAll(Gen.listK(Gen.int())) { listk -> listk.filterMap { diff --git a/settings.gradle b/settings.gradle index 5da190a93..850b17850 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,3 +7,6 @@ include 'arrow-syntax' include 'arrow-core' include 'arrow-core-data' include 'arrow-core-test' + + + From 3076d6d147c1698c3da70da7652f77481d02c8b5 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Tue, 28 Jul 2020 22:02:57 -0500 Subject: [PATCH 04/14] add `padZipWithNull` --- .../src/main/kotlin/arrow/core/ListK.kt | 35 +++++++++---------- .../src/test/kotlin/arrow/core/ListKTest.kt | 9 +++++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index 52a9a4070..88e0748f1 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -212,36 +212,35 @@ data class ListK(private val list: List) : ListKOf, List by list } /** - * Returns a [ListK] containing the transformed values from the original - * [ListK] as long as they are non-null. + * Returns a [ListK] containing the zipped values of the two listKs + * with null for padding. * * Example: * ```kotlin:ank:playground * import arrow.core.* * * //sampleStart - * val evenStrings = listOf(1, 2).k().filterNullMap { - * when (it % 2 == 0) { - * true -> it.toString() - * else -> null - * } - * } // Result: listOf("2").k() + * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) + * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) + * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) * //sampleEnd * * fun main() { - * println("evenStrings = $evenStrings") + * println("padRight = $padRight") + * println("padLeft = $padLeft") + * println("noPadding = $noPadding") * } * ``` */ -// fun padZipWithNull( -// other: ListK -// ): ListK> = -// alignWith(this, other) { ior -> -// ior.fold( -// { it.some() toT Option.empty() }, -// { Option.empty() toT it.some() }, -// { a, b -> a.some() toT b.some() }) -// } + fun padZipWithNull( + other: ListK + ): ListK> = + alignWith(this, other) { ior -> + ior.fold( + { it toT null }, + { null toT it }, + { a, b -> a toT b }) + } /** * Align two Lists as in zipWith, but filling in blanks with None. diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 46b2ec539..474410bb0 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -199,6 +199,15 @@ class ListKTest : UnitSpec() { } } + "padZipWithNull" { + forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> + val left = a.map { it }.k() + List(max(0, b.count() - a.count())) { null }.k() + val right = b.map { it }.k() + List(max(0, a.count() - b.count())) { null }.k() + + a.padZipWithNull(b) == left.zipWith(right) { l, r -> l toT r } + } + } + "filterMap() should map list and filter out None values" { forAll(Gen.listK(Gen.int())) { listk -> listk.filterMap { From 5bca4a9cbb19e9d610aefa68f387b9a756b0ff85 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Tue, 28 Jul 2020 22:18:46 -0500 Subject: [PATCH 05/14] test for `padZipWih` --- arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 474410bb0..5aff5fd5e 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -199,6 +199,14 @@ class ListKTest : UnitSpec() { } } + "padZipWith" { + forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> + val left = a.map { Some(it) }.k() + List(max(0, b.count() - a.count())) { None }.k() + val right = b.map { Some(it) }.k() + List(max(0, a.count() - b.count())) { None }.k() + a.padZipWith(b) { l, r -> Ior.fromOptions(l, r) } == left.zipWith(right) { l, r -> Ior.fromOptions(l, r) } + } + } + "padZipWithNull" { forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> val left = a.map { it }.k() + List(max(0, b.count() - a.count())) { null }.k() From 99c47bd74ce3fbc8f2700cecdf86698e2e5ed8fb Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Wed, 29 Jul 2020 07:25:07 -0500 Subject: [PATCH 06/14] rename nullable `padZipWith` to `padZipWithNull` so it won't break existing type inference --- .../src/main/kotlin/arrow/core/ListK.kt | 33 +++++++++++++++++-- .../src/test/kotlin/arrow/core/ListKTest.kt | 10 +++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index 88e0748f1..d07115080 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -201,6 +201,7 @@ data class ListK(private val list: List) : ListKOf, List by list /** * Align two Lists as in zip, but filling in blanks with None. */ + @Deprecated("Deprecated, use `padZipWithNull` instead", ReplaceWith("padZipWithNull(other: ListK)")) fun padZip( other: ListK ): ListK, Option>> = @@ -212,7 +213,7 @@ data class ListK(private val list: List) : ListKOf, List by list } /** - * Returns a [ListK] containing the zipped values of the two listKs + * Returns a [ListK>] containing the zipped values of the two listKs * with null for padding. * * Example: @@ -245,12 +246,40 @@ data class ListK(private val list: List) : ListKOf, List by list /** * Align two Lists as in zipWith, but filling in blanks with None. */ + @Deprecated("Deprecated, use `padZipWithNull(other: ListK, fa: (A?, B?) -> C)` instead", ReplaceWith("padZipWithNull(other: ListK, fa: (A?, B?) -> C)")) fun padZipWith( other: ListK, fa: (Option, Option) -> C ): ListK = padZip(other).map { fa(it.a, it.b) } + /** + * Returns a [ListK] containing the result of applying some transformation `(A?, B?) -> C` + * on a zip. + * + * Example: + * ```kotlin:ank:playground + * import arrow.core.* + * + * //sampleStart + * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) + * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) + * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) + * //sampleEnd + * + * fun main() { + * println("padRight = $padRight") + * println("padLeft = $padLeft") + * println("noPadding = $noPadding") + * } + * ``` + */ + fun padZipWithNull( + other: ListK, + fa: (A?, B?) -> C + ): ListK = + padZipWithNull(other).map { fa(it.a, it.b) } + /** * Left-padded zipWith. */ @@ -258,7 +287,7 @@ data class ListK(private val list: List) : ListKOf, List by list other: ListK, fab: (Option, B) -> C ): ListK = - padZipWith(other) { a, b -> b.map { fab(a, it) } }.filterMap(::identity) + padZipWith(other) { a: Option, b -> b.map { fab(a, it) } }.filterMap(::identity) /** * Left-padded zip. diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 5aff5fd5e..bfb101f4b 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -203,7 +203,15 @@ class ListKTest : UnitSpec() { forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> val left = a.map { Some(it) }.k() + List(max(0, b.count() - a.count())) { None }.k() val right = b.map { Some(it) }.k() + List(max(0, a.count() - b.count())) { None }.k() - a.padZipWith(b) { l, r -> Ior.fromOptions(l, r) } == left.zipWith(right) { l, r -> Ior.fromOptions(l, r) } + a.padZipWith(b) { l: Option, r: Option -> Ior.fromOptions(l, r) } == left.zipWith(right) { l, r -> Ior.fromOptions(l, r) } + } + } + + "padZipWithNull" { + forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> + val left = a.map { it }.k() + List(max(0, b.count() - a.count())) { null }.k() + val right = b.map { it }.k() + List(max(0, a.count() - b.count())) { null }.k() + a.padZipWithNull(b) { l: Int?, r: Int? -> Ior.fromNullables(l, r) } == left.zipWith(right) { l, r -> Ior.fromNullables(l, r) } } } From 0fec96f7e67daa855ba8e92e97dd795dfb421829 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Wed, 29 Jul 2020 09:02:19 -0500 Subject: [PATCH 07/14] update docs to have expected results --- arrow-core-data/src/main/kotlin/arrow/core/ListK.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index d07115080..f11b07233 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -262,9 +262,9 @@ data class ListK(private val list: List) : ListKOf, List by list * import arrow.core.* * * //sampleStart - * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) - * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) - * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) + * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, null)) + * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(null, "b")) + * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, "b")) * //sampleEnd * * fun main() { From 8fe4026f3046b6c322edadbee12e8da77e1ff996 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Thu, 30 Jul 2020 09:12:17 -0500 Subject: [PATCH 08/14] rename conflicting fn names and fix docs --- .../src/main/kotlin/arrow/core/ListK.kt | 20 +++++++++---------- .../src/test/kotlin/arrow/core/ListKTest.kt | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index f11b07233..fab5c9919 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -221,9 +221,9 @@ data class ListK(private val list: List) : ListKOf, List by list * import arrow.core.* * * //sampleStart - * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) - * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) - * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) + * val padRight = listOf(1, 2).k().padZip(listOf("a").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, null)) + * val padLeft = listOf(1).k().padZip(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(null, "b")) + * val noPadding = listOf(1, 2).k().padZip(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, "b")) * //sampleEnd * * fun main() { @@ -246,7 +246,7 @@ data class ListK(private val list: List) : ListKOf, List by list /** * Align two Lists as in zipWith, but filling in blanks with None. */ - @Deprecated("Deprecated, use `padZipWithNull(other: ListK, fa: (A?, B?) -> C)` instead", ReplaceWith("padZipWithNull(other: ListK, fa: (A?, B?) -> C)")) + @Deprecated("Deprecated, use `padZip(other: ListK, fa: (A?, B?) -> C)` instead", ReplaceWith("padZip(other: ListK, fa: (A?, B?) -> C)")) fun padZipWith( other: ListK, fa: (Option, Option) -> C @@ -262,19 +262,19 @@ data class ListK(private val list: List) : ListKOf, List by list * import arrow.core.* * * //sampleStart - * val padRight = listOf(1, 2).k().padZipWithNull(listOf("a").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, null)) - * val padLeft = listOf(1).k().padZipWithNull(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(null, "b")) - * val noPadding = listOf(1, 2).k().padZipWithNull(listOf("a", "b").k()) // Result: ListK(Tuple2(1, "a"), Tuple2(2, "b")) + * val padZipRight = listOf(1, 2).k().padZip(listOf("a").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a"), Tuple2(2, null)) + * val padZipLeft = listOf(1).k().padZip(listOf("a", "b").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a"), Tuple2(null, "b")) + * val noPadding = listOf(1, 2).k().padZip(listOf("a", "b").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a"), Tuple2(2, "b")) * //sampleEnd * * fun main() { - * println("padRight = $padRight") - * println("padLeft = $padLeft") + * println("padZipRight = $padZipRight") + * println("padZipLeft = $padZipLeft") * println("noPadding = $noPadding") * } * ``` */ - fun padZipWithNull( + fun padZip( other: ListK, fa: (A?, B?) -> C ): ListK = diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index bfb101f4b..f9ac978b1 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -203,15 +203,15 @@ class ListKTest : UnitSpec() { forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> val left = a.map { Some(it) }.k() + List(max(0, b.count() - a.count())) { None }.k() val right = b.map { Some(it) }.k() + List(max(0, a.count() - b.count())) { None }.k() - a.padZipWith(b) { l: Option, r: Option -> Ior.fromOptions(l, r) } == left.zipWith(right) { l, r -> Ior.fromOptions(l, r) } + a.padZipWith(b) { l, r -> Ior.fromOptions(l, r) } == left.zipWith(right) { l, r -> Ior.fromOptions(l, r) } } } - "padZipWithNull" { + "padZip (with map)" { forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> val left = a.map { it }.k() + List(max(0, b.count() - a.count())) { null }.k() val right = b.map { it }.k() + List(max(0, a.count() - b.count())) { null }.k() - a.padZipWithNull(b) { l: Int?, r: Int? -> Ior.fromNullables(l, r) } == left.zipWith(right) { l, r -> Ior.fromNullables(l, r) } + a.padZip(b) { l, r -> Ior.fromNullables(l, r) } == left.zipWith(right) { l, r -> Ior.fromNullables(l, r) } } } From da0360e915cb860653129e631fdc75f8a62145c1 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Thu, 30 Jul 2020 09:53:56 -0500 Subject: [PATCH 09/14] leftPadZip with map --- .../src/main/kotlin/arrow/core/ListK.kt | 28 +++++++++++++++++++ .../src/test/kotlin/arrow/core/ListKTest.kt | 14 ++++++++++ 2 files changed, 42 insertions(+) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index fab5c9919..f0b8ef05a 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -283,12 +283,40 @@ data class ListK(private val list: List) : ListKOf, List by list /** * Left-padded zipWith. */ + @Deprecated("Deprecated, use `leftPadZip(other: ListK, fab: (A?, B) -> C)` instead", ReplaceWith("leftPadZip(other: ListK, fab: (A?, B) -> C)")) fun lpadZipWith( other: ListK, fab: (Option, B) -> C ): ListK = padZipWith(other) { a: Option, b -> b.map { fab(a, it) } }.filterMap(::identity) + /** + * Returns a [ListK] containing the result of applying some transformation `(A?, B) -> C` + * on a zip, excluding all cases where the right value is null. + * + * Example: + * ```kotlin:ank:playground + * import arrow.core.* + * + * //sampleStart + * val left = listOf(1, 2).k().leftPadZip(listOf("a").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a")) + * val right = listOf(1).k().leftPadZip(listOf("a", "b").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a"), Tuple2(null, "b")) + * val both = listOf(1, 2).k().leftPadZip(listOf("a", "b").k()) { l, r -> l toT r }.k() // Result: ListK(Tuple2(1, "a"), Tuple2(2, "b")) + * //sampleEnd + * + * fun main() { + * println("left = $left") + * println("right = $right") + * println("both = $both") + * } + * ``` + */ + fun leftPadZip( + other: ListK, + fab: (A?, B) -> C + ): ListK = + padZip(other) { a: A?, b: B? -> b?.let { fab(a, it) } }.filterNullMap(::identity) + /** * Left-padded zip. */ diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index f9ac978b1..0204b3b4e 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -168,6 +168,20 @@ class ListKTest : UnitSpec() { } } + "leftPadZip (with map)" { + forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> + val left = a.map { it }.k() + List(max(0, b.count() - a.count())) { null }.k() + val right = b.map { it }.k() + List(max(0, a.count() - b.count())) { null }.k() + + val result = + a.leftPadZip(b) { a, b -> + a toT b + } + + result == left.zipWith(right) { l, r -> l toT r }.filter { it.b != null } + } + } + "rpadzip" { forAll(Gen.listK(Gen.int()), Gen.listK(Gen.int())) { a, b -> From 88bcba4f8de840bcdd61071d70e4e4809b024d82 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Fri, 31 Jul 2020 08:00:16 -0500 Subject: [PATCH 10/14] revert weird spacing added to `settings.gradle` --- settings.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/settings.gradle b/settings.gradle index 850b17850..5da190a93 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,3 @@ include 'arrow-syntax' include 'arrow-core' include 'arrow-core-data' include 'arrow-core-test' - - - From 937d4acd75694e3cd1559b1ba5b3a72d875cc0dd Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Thu, 6 Aug 2020 19:11:59 -0500 Subject: [PATCH 11/14] rename `filterNullMap` -> `mapNotNull` --- arrow-core-data/src/main/kotlin/arrow/core/ListK.kt | 8 ++++---- arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index f0b8ef05a..0272e1342 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -167,7 +167,7 @@ data class ListK(private val list: List) : ListKOf, List by list } } - @Deprecated("Deprecated, use filterNullMap(f: (A) -> B?) instead", ReplaceWith("filterNullMap(f: (A) -> B?)")) + @Deprecated("Deprecated, use mapNotNull(f: (A) -> B?) instead", ReplaceWith("mapNotNull(f: (A) -> B?)")) fun filterMap(f: (A) -> Option): ListK = flatMap { a -> f(a).fold({ empty() }, { just(it) }) } @@ -180,7 +180,7 @@ data class ListK(private val list: List) : ListKOf, List by list * import arrow.core.* * * //sampleStart - * val evenStrings = listOf(1, 2).k().filterNullMap { + * val evenStrings = listOf(1, 2).k().mapNotNull { * when (it % 2 == 0) { * true -> it.toString() * else -> null @@ -193,7 +193,7 @@ data class ListK(private val list: List) : ListKOf, List by list * } * ``` */ - fun filterNullMap(f: (A) -> B?): ListK = + fun mapNotNull(f: (A) -> B?): ListK = flatMap { a -> mapN(f(a)) { just(it) } ?: empty() } override fun hashCode(): Int = list.hashCode() @@ -315,7 +315,7 @@ data class ListK(private val list: List) : ListKOf, List by list other: ListK, fab: (A?, B) -> C ): ListK = - padZip(other) { a: A?, b: B? -> b?.let { fab(a, it) } }.filterNullMap(::identity) + padZip(other) { a: A?, b: B? -> b?.let { fab(a, it) } }.mapNotNull(::identity) /** * Left-padded zip. diff --git a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt index 0204b3b4e..8f7db68a1 100644 --- a/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt +++ b/arrow-core-data/src/test/kotlin/arrow/core/ListKTest.kt @@ -249,9 +249,9 @@ class ListKTest : UnitSpec() { } } - "filterNullMap() should map list and filter out null values" { + "mapNotNull() should map list and filter out null values" { forAll(Gen.listK(Gen.int())) { listk -> - listk.filterNullMap { + listk.mapNotNull { when (it % 2 == 0) { true -> it.toString() else -> null From 88158a3ec890f1c3a47ed1f8632ce01dceaa445d Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Mon, 10 Aug 2020 14:36:34 -0500 Subject: [PATCH 12/14] Update arrow-core-data/src/main/kotlin/arrow/core/ListK.kt Co-authored-by: Alberto Ballano --- arrow-core-data/src/main/kotlin/arrow/core/ListK.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index 0272e1342..355da327e 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -185,7 +185,7 @@ data class ListK(private val list: List) : ListKOf, List by list * true -> it.toString() * else -> null * } - * } // Result: listOf("2").k() + * } * //sampleEnd * * fun main() { From ab193088b6307a9cd39d437c2fd9604b0467a7bc Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Mon, 10 Aug 2020 14:36:41 -0500 Subject: [PATCH 13/14] Update arrow-core-data/src/main/kotlin/arrow/core/ListK.kt Co-authored-by: Alberto Ballano --- arrow-core-data/src/main/kotlin/arrow/core/ListK.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index 355da327e..fa2b4f60c 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -173,7 +173,7 @@ data class ListK(private val list: List) : ListKOf, List by list /** * Returns a [ListK] containing the transformed values from the original - * [ListK] as long as they are non-null. + * [ListK] filtering out any null value. * * Example: * ```kotlin:ank:playground From 95ab8d241c2bc9409075db3f901bbc6697a26602 Mon Sep 17 00:00:00 2001 From: Tavish Pegram Date: Mon, 10 Aug 2020 14:36:48 -0500 Subject: [PATCH 14/14] Update arrow-core-data/src/main/kotlin/arrow/core/ListK.kt Co-authored-by: Alberto Ballano --- arrow-core-data/src/main/kotlin/arrow/core/ListK.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt index fa2b4f60c..b8ffa6d97 100644 --- a/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt +++ b/arrow-core-data/src/main/kotlin/arrow/core/ListK.kt @@ -194,7 +194,7 @@ data class ListK(private val list: List) : ListKOf, List by list * ``` */ fun mapNotNull(f: (A) -> B?): ListK = - flatMap { a -> mapN(f(a)) { just(it) } ?: empty() } + flatMap { a -> f(a)?.let { just(it) } ?: empty() } override fun hashCode(): Int = list.hashCode()