From c9ab7fbcb2cfaadca238685ff944cfbfada48447 Mon Sep 17 00:00:00 2001 From: Ambrus Adrian Date: Tue, 22 Oct 2019 17:36:42 +0200 Subject: [PATCH 1/3] Fix Json.add and Json.merge operations * Json.add should return object with added/updated field * Json.merge should work as Map.plus * Json.toList should use Pair to Tuple2 function * Add test cases for add and merge operations --- .../src/main/kotlin/helios/core/helios.kt | 13 +- .../kotlin/helios/core/JsonOperationTest.kt | 125 ++++++++++++++++++ 2 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt diff --git a/helios-core/src/main/kotlin/helios/core/helios.kt b/helios-core/src/main/kotlin/helios/core/helios.kt index 07f7d22..e3443c4 100644 --- a/helios-core/src/main/kotlin/helios/core/helios.kt +++ b/helios-core/src/main/kotlin/helios/core/helios.kt @@ -76,8 +76,9 @@ sealed class Json { is JsBoolean -> ifJsBoolean(this) } - fun add(key: String, value: Json): JsObject = - JsObject(hashMapOf(key to value)) + fun add(key: String, value: Json): Json = this.asJsObject() + .map { JsObject(it.value + (key to value)) } + .getOrElse { this } fun asJsString(): Option = (this as? JsString)?.some() ?: none() @@ -98,10 +99,8 @@ sealed class Json { (this as? JsNull)?.some() ?: none() fun merge(that: Json): Json = - Option.applicative().map(asJsObject(), that.asJsObject()) { (lhs, rhs) -> - lhs.toList().fold(rhs) { acc, (key, value) -> - rhs[key].fold({ acc.add(key, value) }, { r -> acc.add(key, value.merge(r)) }) - } + Option.applicative().map(asJsObject(), that.asJsObject()) { + JsObject(it.a.value + it.b.value) }.fix().getOrElse { that } abstract fun noSpaces(): String @@ -357,7 +356,7 @@ data class JsObject(val value: Map) : Json() { JsObject(keyValues.map { it.a to it.b }.toMap()) } - fun toList(): List> = value.toList().map { it.first toT it.second } + fun toList(): List> = value.toList().map { it.toTuple2() } override fun noSpaces(): String = value.map { (k, v) -> """"$k":${v.noSpaces()}""" }.joinToString( diff --git a/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt b/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt new file mode 100644 index 0000000..ed30815 --- /dev/null +++ b/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt @@ -0,0 +1,125 @@ +package helios.core + +import arrow.test.UnitSpec +import helios.instances.json.eq.eq +import io.kotlintest.shouldBe + +class JsonOperationTest : UnitSpec() { + init { + "add operation adds JsString field" { + Json.eq().run { + val actual = JsObject( + "latitude" to JsString("123") + ).add("longitude", JsString("124")) + + val expected = JsObject( + "latitude" to JsString("123"), + "longitude" to JsString("124") + ) + + actual.eqv(expected) shouldBe true + } + } + + "add operation updates existing JsString field" { + Json.eq().run { + val actual = JsObject( + "latitude" to JsString("123"), + "longitude" to JsString("124") + ).add("longitude", JsString("125")) + + val expected = JsObject( + "latitude" to JsString("123"), + "longitude" to JsString("125") + ) + + actual.eqv(expected) shouldBe true + } + } + + "add operation adds JsObject field" { + Json.eq().run { + val actual = JsObject( + "latitude" to JsString("123") + ).add( + "longitude", JsObject( + "type" to JsString("WGS84"), + "value" to JsString("124") + ) + ) + + val expected = JsObject( + mapOf( + "latitude" to JsString("123"), + "longitude" to JsObject( + "type" to JsString("WGS84"), + "value" to JsString("124") + ) + ) + ) + + actual.eqv(expected) shouldBe true + } + } + + "add operation updates existing JsObject field" { + Json.eq().run { + val actual = JsObject( + "latitude" to JsString("123"), + "longitude" to JsObject( + "type" to JsString("WGS84"), + "value" to JsString("124") + ) + ).add( + "longitude", JsObject( + "type" to JsString("WGS84"), + "value" to JsString("125") + ) + ) + + val expected = JsObject( + mapOf( + "latitude" to JsString("123"), + "longitude" to JsObject( + "type" to JsString("WGS84"), + "value" to JsString("125") + ) + ) + ) + + actual.eqv(expected) shouldBe true + } + } + + "merge two objects together" { + Json.eq().run { + val a = JsObject( + "latitude" to JsString("123"), + "longitude" to JsObject( + "type" to JsString("WGS84"), + "value" to JsString("125") + ) + ) + + val b = JsObject( + "location" to JsString("nyc") + ) + + val actual = a.merge(b) + + val expected = JsObject( + mapOf( + "latitude" to JsString("123"), + "longitude" to JsObject( + "type" to JsString("WGS84"), + "value" to JsString("125") + ), + "location" to JsString("nyc") + ) + ) + + actual.eqv(expected) shouldBe true + } + } + } +} From e012fc048c2cbbe57841b4a38f3bbe1dea7cf72a Mon Sep 17 00:00:00 2001 From: Ambrus Adrian Date: Mon, 2 Dec 2019 09:43:16 +0100 Subject: [PATCH 2/3] Address PR comments * move add operation from Json to JsObject * add Monoid to Json.merge operation --- .../src/main/kotlin/helios/core/helios.kt | 13 +- .../src/main/kotlin/helios/core/monoid.kt | 104 +++++++++++++++ .../kotlin/helios/instances/instancesEq.kt | 7 + .../helios/instances/instancesMonoid.kt | 46 +++++++ .../helios/instances/instancesSemigroup.kt | 63 +++++++++ .../kotlin/helios/core/JsonOperationTest.kt | 125 ------------------ .../src/test/kotlin/helios/core/MonoidTest.kt | 30 +++++ .../test/kotlin/helios/optics/instances.kt | 24 ---- 8 files changed, 255 insertions(+), 157 deletions(-) create mode 100644 helios-core/src/main/kotlin/helios/core/monoid.kt create mode 100644 helios-core/src/main/kotlin/helios/instances/instancesMonoid.kt create mode 100644 helios-core/src/main/kotlin/helios/instances/instancesSemigroup.kt delete mode 100644 helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt create mode 100644 helios-core/src/test/kotlin/helios/core/MonoidTest.kt diff --git a/helios-core/src/main/kotlin/helios/core/helios.kt b/helios-core/src/main/kotlin/helios/core/helios.kt index e3443c4..5f24a2f 100644 --- a/helios-core/src/main/kotlin/helios/core/helios.kt +++ b/helios-core/src/main/kotlin/helios/core/helios.kt @@ -1,7 +1,9 @@ package helios.core import arrow.core.* +import arrow.core.extensions.monoid import arrow.core.extensions.option.applicative.applicative +import arrow.typeclasses.Monoid import helios.instances.HeliosFacade import helios.instances.jsarray.eq.eq import helios.instances.jsnumber.eq.eq @@ -76,10 +78,6 @@ sealed class Json { is JsBoolean -> ifJsBoolean(this) } - fun add(key: String, value: Json): Json = this.asJsObject() - .map { JsObject(it.value + (key to value)) } - .getOrElse { this } - fun asJsString(): Option = (this as? JsString)?.some() ?: none() @@ -98,10 +96,7 @@ sealed class Json { fun asJsNull(): Option = (this as? JsNull)?.some() ?: none() - fun merge(that: Json): Json = - Option.applicative().map(asJsObject(), that.asJsObject()) { - JsObject(it.a.value + it.b.value) - }.fix().getOrElse { that } + fun merge(that: Json, M: Monoid): Json = M.combineAll(listOf(this, that)) abstract fun noSpaces(): String @@ -356,6 +351,8 @@ data class JsObject(val value: Map) : Json() { JsObject(keyValues.map { it.a to it.b }.toMap()) } + fun add(key: String, value: Json): Json = JsObject(this.value + (key to value)) + fun toList(): List> = value.toList().map { it.toTuple2() } override fun noSpaces(): String = diff --git a/helios-core/src/main/kotlin/helios/core/monoid.kt b/helios-core/src/main/kotlin/helios/core/monoid.kt new file mode 100644 index 0000000..33137d0 --- /dev/null +++ b/helios-core/src/main/kotlin/helios/core/monoid.kt @@ -0,0 +1,104 @@ +package helios.core + +import arrow.core.extensions.semigroup +import arrow.data.ListK +import arrow.data.extensions.listk.semigroup.semigroup +import arrow.data.k +import arrow.typeclasses.Monoid +import arrow.typeclasses.Semigroup + +interface JsIntSemigroup : Semigroup { + override fun JsInt.combine(b: JsInt): JsInt = JsInt(Int.semigroup().run { + value.combine(b.value) + }) +} + +interface JsIntMonoid : Monoid, JsIntSemigroup { + override fun empty(): JsInt = JsInt(0) +} + +interface JsLongSemigroup : Semigroup { + override fun JsLong.combine(b: JsLong): JsLong = JsLong(Long.semigroup().run { + value.combine(b.value) + }) +} + +interface JsLongMonoid : Monoid, JsLongSemigroup { + override fun empty(): JsLong = JsLong(0L) +} + +interface JsFloatSemigroup : Semigroup { + override fun JsFloat.combine(b: JsFloat): JsFloat = JsFloat(Float.semigroup().run { + value.combine(b.value) + }) +} + +interface JsFloatMonoid : Monoid, JsFloatSemigroup { + override fun empty(): JsFloat = JsFloat(0f) +} + +interface JsDoubleSemigroup : Semigroup { + override fun JsDouble.combine(b: JsDouble): JsDouble = JsDouble(Double.semigroup().run { + value.combine(b.value) + }) +} + +interface JsDoubleMonoid : Monoid, JsDoubleSemigroup { + override fun empty(): JsDouble = JsDouble(0.0) +} + +interface JsStringSemigroup : Semigroup { + override fun JsString.combine(b: JsString): JsString = JsString(String.semigroup().run { + value.toString().combine(b.value.toString()) + }) +} + +interface JsStringMonoid : Monoid, JsStringSemigroup { + override fun empty(): JsString = JsString("") +} + +interface JsArraySemigroup : Semigroup { + override fun JsArray.combine(b: JsArray): JsArray = JsArray(ListK.semigroup().run { + value.k().combine(b.value.k()) + }) +} + +interface JsArrayMonoid : Monoid, JsArraySemigroup { + override fun empty(): JsArray = JsArray(emptyList()) +} + +interface JsObjectSemigroup : Semigroup { + override fun JsObject.combine(b: JsObject): JsObject = JsObject(value + b.value) +} + +interface JsObjectMonoid : Monoid, JsObjectSemigroup { + override fun empty(): JsObject = JsObject(emptyMap()) +} + +fun JsInt.Companion.semigroup(): JsIntSemigroup = object : JsIntSemigroup { } + +fun JsInt.Companion.monoid(): JsIntMonoid = object : JsIntMonoid { } + +fun JsLong.Companion.semigroup(): JsLongSemigroup = object : JsLongSemigroup { } + +fun JsLong.Companion.monoid(): JsLongMonoid = object : JsLongMonoid { } + +fun JsFloat.Companion.semigroup(): JsFloatSemigroup = object : JsFloatSemigroup { } + +fun JsFloat.Companion.monoid(): JsFloatMonoid = object : JsFloatMonoid { } + +fun JsDouble.Companion.semigroup(): JsDoubleSemigroup = object : JsDoubleSemigroup { } + +fun JsDouble.Companion.monoid(): JsDoubleMonoid = object : JsDoubleMonoid { } + +fun JsString.Companion.semigroup(): JsStringSemigroup = object : JsStringSemigroup { } + +fun JsString.Companion.monoid(): JsStringMonoid = object : JsStringMonoid { } + +fun JsArray.Companion.semigroup(): JsArraySemigroup = object : JsArraySemigroup { } + +fun JsArray.Companion.monoid(): JsArrayMonoid = object : JsArrayMonoid { } + +fun JsObject.Companion.semigroup(): JsObjectSemigroup = object : JsObjectSemigroup { } + +fun JsObject.Companion.monoid(): JsObjectMonoid = object : JsObjectMonoid { } diff --git a/helios-core/src/main/kotlin/helios/instances/instancesEq.kt b/helios-core/src/main/kotlin/helios/instances/instancesEq.kt index 49186c3..7442ac2 100644 --- a/helios-core/src/main/kotlin/helios/instances/instancesEq.kt +++ b/helios-core/src/main/kotlin/helios/instances/instancesEq.kt @@ -10,6 +10,13 @@ import helios.instances.jsnumber.eq.eq import helios.instances.jsobject.eq.eq import helios.instances.json.eq.eq +@extension +interface JsStringEq : Eq { + override fun JsString.eqv(b: JsString): Boolean = with(String.eq()) { + value.toString().eqv(b.value.toString()) + } +} + @extension interface JsObjectEq : Eq { override fun JsObject.eqv(b: JsObject): Boolean = with(Json.eq()) { diff --git a/helios-core/src/main/kotlin/helios/instances/instancesMonoid.kt b/helios-core/src/main/kotlin/helios/instances/instancesMonoid.kt new file mode 100644 index 0000000..5abd621 --- /dev/null +++ b/helios-core/src/main/kotlin/helios/instances/instancesMonoid.kt @@ -0,0 +1,46 @@ +package helios.instances + +import arrow.extension +import arrow.typeclasses.Monoid +import helios.core.JsArray +import helios.core.JsDouble +import helios.core.JsFloat +import helios.core.JsInt +import helios.core.JsLong +import helios.core.JsObject +import helios.core.JsString + +@extension +interface JsIntMonoid : Monoid, JsIntSemigroup { + override fun empty(): JsInt = JsInt(0) +} + +@extension +interface JsLongMonoid : Monoid, JsLongSemigroup { + override fun empty(): JsLong = JsLong(0L) +} + +@extension +interface JsFloatMonoid : Monoid, JsFloatSemigroup { + override fun empty(): JsFloat = JsFloat(0f) +} + +@extension +interface JsDoubleMonoid : Monoid, JsDoubleSemigroup { + override fun empty(): JsDouble = JsDouble(0.0) +} + +@extension +interface JsStringMonoid : Monoid, JsStringSemigroup { + override fun empty(): JsString = JsString("") +} + +@extension +interface JsArrayMonoid : Monoid, JsArraySemigroup { + override fun empty(): JsArray = JsArray(emptyList()) +} + +@extension +interface JsObjectMonoid : Monoid, JsObjectSemigroup { + override fun empty(): JsObject = JsObject(emptyMap()) +} diff --git a/helios-core/src/main/kotlin/helios/instances/instancesSemigroup.kt b/helios-core/src/main/kotlin/helios/instances/instancesSemigroup.kt new file mode 100644 index 0000000..a5e179c --- /dev/null +++ b/helios-core/src/main/kotlin/helios/instances/instancesSemigroup.kt @@ -0,0 +1,63 @@ +package helios.instances + +import arrow.core.extensions.semigroup +import arrow.data.ListK +import arrow.data.extensions.listk.semigroup.semigroup +import arrow.data.k +import arrow.extension +import arrow.typeclasses.Semigroup +import helios.core.JsArray +import helios.core.JsDouble +import helios.core.JsFloat +import helios.core.JsInt +import helios.core.JsLong +import helios.core.JsObject +import helios.core.JsString +import helios.core.Json + +@extension +interface JsIntSemigroup : Semigroup { + override fun JsInt.combine(b: JsInt): JsInt = JsInt(Int.semigroup().run { + value.combine(b.value) + }) +} + +@extension +interface JsLongSemigroup : Semigroup { + override fun JsLong.combine(b: JsLong): JsLong = JsLong(Long.semigroup().run { + value.combine(b.value) + }) +} + +@extension +interface JsFloatSemigroup : Semigroup { + override fun JsFloat.combine(b: JsFloat): JsFloat = JsFloat(Float.semigroup().run { + value.combine(b.value) + }) +} + +@extension +interface JsDoubleSemigroup : Semigroup { + override fun JsDouble.combine(b: JsDouble): JsDouble = JsDouble(Double.semigroup().run { + value.combine(b.value) + }) +} + +@extension +interface JsStringSemigroup : Semigroup { + override fun JsString.combine(b: JsString): JsString = JsString(String.semigroup().run { + value.toString().combine(b.value.toString()) + }) +} + +@extension +interface JsArraySemigroup : Semigroup { + override fun JsArray.combine(b: JsArray): JsArray = JsArray(ListK.semigroup().run { + value.k().combine(b.value.k()) + }) +} + +@extension +interface JsObjectSemigroup : Semigroup { + override fun JsObject.combine(b: JsObject): JsObject = JsObject(value + b.value) +} diff --git a/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt b/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt deleted file mode 100644 index ed30815..0000000 --- a/helios-core/src/test/kotlin/helios/core/JsonOperationTest.kt +++ /dev/null @@ -1,125 +0,0 @@ -package helios.core - -import arrow.test.UnitSpec -import helios.instances.json.eq.eq -import io.kotlintest.shouldBe - -class JsonOperationTest : UnitSpec() { - init { - "add operation adds JsString field" { - Json.eq().run { - val actual = JsObject( - "latitude" to JsString("123") - ).add("longitude", JsString("124")) - - val expected = JsObject( - "latitude" to JsString("123"), - "longitude" to JsString("124") - ) - - actual.eqv(expected) shouldBe true - } - } - - "add operation updates existing JsString field" { - Json.eq().run { - val actual = JsObject( - "latitude" to JsString("123"), - "longitude" to JsString("124") - ).add("longitude", JsString("125")) - - val expected = JsObject( - "latitude" to JsString("123"), - "longitude" to JsString("125") - ) - - actual.eqv(expected) shouldBe true - } - } - - "add operation adds JsObject field" { - Json.eq().run { - val actual = JsObject( - "latitude" to JsString("123") - ).add( - "longitude", JsObject( - "type" to JsString("WGS84"), - "value" to JsString("124") - ) - ) - - val expected = JsObject( - mapOf( - "latitude" to JsString("123"), - "longitude" to JsObject( - "type" to JsString("WGS84"), - "value" to JsString("124") - ) - ) - ) - - actual.eqv(expected) shouldBe true - } - } - - "add operation updates existing JsObject field" { - Json.eq().run { - val actual = JsObject( - "latitude" to JsString("123"), - "longitude" to JsObject( - "type" to JsString("WGS84"), - "value" to JsString("124") - ) - ).add( - "longitude", JsObject( - "type" to JsString("WGS84"), - "value" to JsString("125") - ) - ) - - val expected = JsObject( - mapOf( - "latitude" to JsString("123"), - "longitude" to JsObject( - "type" to JsString("WGS84"), - "value" to JsString("125") - ) - ) - ) - - actual.eqv(expected) shouldBe true - } - } - - "merge two objects together" { - Json.eq().run { - val a = JsObject( - "latitude" to JsString("123"), - "longitude" to JsObject( - "type" to JsString("WGS84"), - "value" to JsString("125") - ) - ) - - val b = JsObject( - "location" to JsString("nyc") - ) - - val actual = a.merge(b) - - val expected = JsObject( - mapOf( - "latitude" to JsString("123"), - "longitude" to JsObject( - "type" to JsString("WGS84"), - "value" to JsString("125") - ), - "location" to JsString("nyc") - ) - ) - - actual.eqv(expected) shouldBe true - } - } - } -} diff --git a/helios-core/src/test/kotlin/helios/core/MonoidTest.kt b/helios-core/src/test/kotlin/helios/core/MonoidTest.kt new file mode 100644 index 0000000..a857661 --- /dev/null +++ b/helios-core/src/test/kotlin/helios/core/MonoidTest.kt @@ -0,0 +1,30 @@ +package helios.core + +import arrow.test.UnitSpec +import arrow.test.laws.MonoidLaws +import arrow.test.laws.SemigroupLaws +import helios.instances.jsstring.eq.eq +import io.kotlintest.properties.Gen + +class MonoidTest : UnitSpec() { + + init { + testLaws( + SemigroupLaws.laws( + JsString.semigroup(), + JsString("a"), + JsString("b"), + JsString("c"), + JsString.eq() + ) + ) + + testLaws( + MonoidLaws.laws( + JsString.monoid(), + Gen.string().map { JsString(it) }, + JsString.eq() + ) + ) + } +} diff --git a/helios-optics/src/test/kotlin/helios/optics/instances.kt b/helios-optics/src/test/kotlin/helios/optics/instances.kt index 0106ebd..e2ec400 100644 --- a/helios-optics/src/test/kotlin/helios/optics/instances.kt +++ b/helios-optics/src/test/kotlin/helios/optics/instances.kt @@ -1,24 +1,14 @@ package helios.optics -import arrow.core.None -import arrow.core.Option -import arrow.core.extensions.option.eq.eq import arrow.test.UnitSpec import arrow.test.generators.functionAToB -import arrow.test.generators.option -import arrow.test.laws.LensLaws import arrow.test.laws.OptionalLaws import arrow.test.laws.TraversalLaws import arrow.typeclasses.Eq -import arrow.typeclasses.Monoid import helios.core.JsArray import helios.core.JsObject -import helios.core.Json -import helios.instances.jsobject.eq.eq -import helios.instances.json.eq.eq import helios.optics.jsarray.each.each import helios.optics.jsarray.index.index -import helios.optics.jsobject.at.at import helios.optics.jsobject.each.each import helios.optics.jsobject.index.index import helios.test.generators.alphaStr @@ -76,19 +66,5 @@ class InstancesTest : UnitSpec() { EQListB = Eq.any() ) ) - - testLaws(LensLaws.laws( - lensGen = Gen.alphaStr().map { JsObject.at().at(it) }, - aGen = Gen.jsObject(), - bGen = Gen.option(Gen.json()), - funcGen = Gen.functionAToB(Gen.option(Gen.json())), - EQA = JsObject.eq(), - EQB = Option.eq(Json.eq()), - MB = object : Monoid> { - override fun Option.combine(b: Option) = flatMap { a -> b.map { a.merge(it) } } - override fun empty(): Option = None - } - )) - } } \ No newline at end of file From b04d5545681f6c7531cfbd9c83f7f7303b688a07 Mon Sep 17 00:00:00 2001 From: Ambrus Adrian Date: Mon, 2 Dec 2019 14:11:08 +0100 Subject: [PATCH 3/3] Delete manual Monoid and Semigroup implementations --- helios-core/build.gradle | 2 +- .../src/main/kotlin/helios/core/monoid.kt | 104 ------------------ .../src/test/kotlin/helios/core/MonoidTest.kt | 2 + 3 files changed, 3 insertions(+), 105 deletions(-) delete mode 100644 helios-core/src/main/kotlin/helios/core/monoid.kt diff --git a/helios-core/build.gradle b/helios-core/build.gradle index 57f1045..a38cef0 100644 --- a/helios-core/build.gradle +++ b/helios-core/build.gradle @@ -14,7 +14,7 @@ dependencies { testImplementation("io.kotest:kotest-runner-junit5:$kotlinTestVersion") testImplementation("io.kotest:kotest-assertions-arrow:$kotlinTestVersion") testImplementation("io.arrow-kt:arrow-test:$arrowVersion") - + kaptTest project(":helios-meta") kaptTest "io.arrow-kt:arrow-meta:$arrowVersion" diff --git a/helios-core/src/main/kotlin/helios/core/monoid.kt b/helios-core/src/main/kotlin/helios/core/monoid.kt deleted file mode 100644 index a1154ad..0000000 --- a/helios-core/src/main/kotlin/helios/core/monoid.kt +++ /dev/null @@ -1,104 +0,0 @@ -package helios.core - -import arrow.core.ListK -import arrow.core.extensions.listk.semigroup.semigroup -import arrow.core.extensions.semigroup -import arrow.core.k -import arrow.typeclasses.Monoid -import arrow.typeclasses.Semigroup - -interface JsIntSemigroup : Semigroup { - override fun JsInt.combine(b: JsInt): JsInt = JsInt(Int.semigroup().run { - value.combine(b.value) - }) -} - -interface JsIntMonoid : Monoid, JsIntSemigroup { - override fun empty(): JsInt = JsInt(0) -} - -interface JsLongSemigroup : Semigroup { - override fun JsLong.combine(b: JsLong): JsLong = JsLong(Long.semigroup().run { - value.combine(b.value) - }) -} - -interface JsLongMonoid : Monoid, JsLongSemigroup { - override fun empty(): JsLong = JsLong(0L) -} - -interface JsFloatSemigroup : Semigroup { - override fun JsFloat.combine(b: JsFloat): JsFloat = JsFloat(Float.semigroup().run { - value.combine(b.value) - }) -} - -interface JsFloatMonoid : Monoid, JsFloatSemigroup { - override fun empty(): JsFloat = JsFloat(0f) -} - -interface JsDoubleSemigroup : Semigroup { - override fun JsDouble.combine(b: JsDouble): JsDouble = JsDouble(Double.semigroup().run { - value.combine(b.value) - }) -} - -interface JsDoubleMonoid : Monoid, JsDoubleSemigroup { - override fun empty(): JsDouble = JsDouble(0.0) -} - -interface JsStringSemigroup : Semigroup { - override fun JsString.combine(b: JsString): JsString = JsString(String.semigroup().run { - value.toString().combine(b.value.toString()) - }) -} - -interface JsStringMonoid : Monoid, JsStringSemigroup { - override fun empty(): JsString = JsString("") -} - -interface JsArraySemigroup : Semigroup { - override fun JsArray.combine(b: JsArray): JsArray = JsArray(ListK.semigroup().run { - value.k().combine(b.value.k()) - }) -} - -interface JsArrayMonoid : Monoid, JsArraySemigroup { - override fun empty(): JsArray = JsArray(emptyList()) -} - -interface JsObjectSemigroup : Semigroup { - override fun JsObject.combine(b: JsObject): JsObject = JsObject(value + b.value) -} - -interface JsObjectMonoid : Monoid, JsObjectSemigroup { - override fun empty(): JsObject = JsObject(emptyMap()) -} - -fun JsInt.Companion.semigroup(): JsIntSemigroup = object : JsIntSemigroup { } - -fun JsInt.Companion.monoid(): JsIntMonoid = object : JsIntMonoid { } - -fun JsLong.Companion.semigroup(): JsLongSemigroup = object : JsLongSemigroup { } - -fun JsLong.Companion.monoid(): JsLongMonoid = object : JsLongMonoid { } - -fun JsFloat.Companion.semigroup(): JsFloatSemigroup = object : JsFloatSemigroup { } - -fun JsFloat.Companion.monoid(): JsFloatMonoid = object : JsFloatMonoid { } - -fun JsDouble.Companion.semigroup(): JsDoubleSemigroup = object : JsDoubleSemigroup { } - -fun JsDouble.Companion.monoid(): JsDoubleMonoid = object : JsDoubleMonoid { } - -fun JsString.Companion.semigroup(): JsStringSemigroup = object : JsStringSemigroup { } - -fun JsString.Companion.monoid(): JsStringMonoid = object : JsStringMonoid { } - -fun JsArray.Companion.semigroup(): JsArraySemigroup = object : JsArraySemigroup { } - -fun JsArray.Companion.monoid(): JsArrayMonoid = object : JsArrayMonoid { } - -fun JsObject.Companion.semigroup(): JsObjectSemigroup = object : JsObjectSemigroup { } - -fun JsObject.Companion.monoid(): JsObjectMonoid = object : JsObjectMonoid { } diff --git a/helios-core/src/test/kotlin/helios/core/MonoidTest.kt b/helios-core/src/test/kotlin/helios/core/MonoidTest.kt index a857661..f6948ab 100644 --- a/helios-core/src/test/kotlin/helios/core/MonoidTest.kt +++ b/helios-core/src/test/kotlin/helios/core/MonoidTest.kt @@ -4,6 +4,8 @@ import arrow.test.UnitSpec import arrow.test.laws.MonoidLaws import arrow.test.laws.SemigroupLaws import helios.instances.jsstring.eq.eq +import helios.instances.jsstring.monoid.monoid +import helios.instances.jsstring.semigroup.semigroup import io.kotlintest.properties.Gen class MonoidTest : UnitSpec() {