From 2b9d9b14842fc7a7630a6468c38d8c7bbfa60eb8 Mon Sep 17 00:00:00 2001 From: pakoito Date: Sat, 16 Sep 2017 00:15:52 +0100 Subject: [PATCH] Observable Kind Wrapper --- .../kategory/effects/data/ObservableKW.kt | 64 +++++++++++ .../kategory/effects/data/ObservableW.kt | 64 ----------- .../effects/instances/ObservableWInstances.kt | 104 +++++++++--------- .../kategory/effects/data/ObservableWTests.kt | 28 ++--- 4 files changed, 130 insertions(+), 130 deletions(-) create mode 100644 kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableKW.kt delete mode 100644 kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableW.kt diff --git a/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableKW.kt b/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableKW.kt new file mode 100644 index 00000000000..68d3f3a2dc2 --- /dev/null +++ b/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableKW.kt @@ -0,0 +1,64 @@ +package kategory + +import io.reactivex.Observable +import io.reactivex.ObservableEmitter + +fun Observable.k(): ObservableKW = ObservableKW(this) + +fun ObservableKWKind.value(): Observable = + this.ev().observable + +@higherkind +@deriving(Functor::class, Applicative::class, AsyncContext::class) +data class ObservableKW(val observable: Observable) : ObservableKWKind { + fun map(f: (A) -> B): ObservableKW = + observable.map(f).k() + + fun ap(fa: ObservableKWKind<(A) -> B>): ObservableKW = + flatMap { a -> fa.ev().map { ff -> ff(a) } } + + fun flatMap(f: (A) -> ObservableKW): ObservableKW = + observable.flatMap { f(it).observable }.k() + + fun concatMap(f: (A) -> ObservableKW): ObservableKW = + observable.concatMap { f(it).observable }.k() + + fun switchMap(f: (A) -> ObservableKW): ObservableKW = + observable.switchMap { f(it).observable }.k() + + companion object { + fun pure(a: A): ObservableKW = + Observable.just(a).k() + + fun raiseError(t: Throwable): ObservableKW = + Observable.error(t).k() + + fun runAsync(fa: Proc): ObservableKW = + Observable.create { emitter: ObservableEmitter -> + fa { either: Either -> + either.fold({ + emitter.onError(it) + }, { + emitter.onNext(it) + emitter.onComplete() + }) + + } + }.k() + + fun monadFlat(): ObservableKWFlatMonadInstance = ObservableKWFlatMonadInstanceImplicits.instance() + + fun monadConcat(): ObservableKWConcatMonadInstance = ObservableKWConcatMonadInstanceImplicits.instance() + + fun monadSwitch(): ObservableKWSwitchMonadInstance = ObservableKWSwitchMonadInstanceImplicits.instance() + + fun monadErrorFlat(): ObservableKWFlatMonadErrorInstance = ObservableKWFlatMonadErrorInstanceImplicits.instance() + + fun monadErrorConcat(): ObservableKWConcatMonadErrorInstance = ObservableKWConcatMonadErrorInstanceImplicits.instance() + + fun monadErrorSwitch(): ObservableKWSwitchMonadErrorInstance = ObservableKWSwitchMonadErrorInstanceImplicits.instance() + } +} + +fun ObservableKW.handleErrorWith(function: (Throwable) -> ObservableKW): ObservableKW = + this.observable.onErrorResumeNext { t: Throwable -> function(t).observable }.k() \ No newline at end of file diff --git a/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableW.kt b/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableW.kt deleted file mode 100644 index 16363dd1527..00000000000 --- a/kategory-effects-rx2/src/main/kotlin/kategory/effects/data/ObservableW.kt +++ /dev/null @@ -1,64 +0,0 @@ -package kategory - -import io.reactivex.Observable -import io.reactivex.ObservableEmitter - -fun Observable.k(): ObservableW = ObservableW(this) - -fun ObservableWKind.value(): Observable = - this.ev().observable - -@higherkind -@deriving(Functor::class, Applicative::class, AsyncContext::class) -data class ObservableW(val observable: Observable) : ObservableWKind { - fun map(f: (A) -> B): ObservableW = - observable.map(f).k() - - fun ap(fa: ObservableWKind<(A) -> B>): ObservableW = - flatMap { a -> fa.ev().map { ff -> ff(a) } } - - fun flatMap(f: (A) -> ObservableW): ObservableW = - observable.flatMap { f(it).observable }.k() - - fun concatMap(f: (A) -> ObservableW): ObservableW = - observable.concatMap { f(it).observable }.k() - - fun switchMap(f: (A) -> ObservableW): ObservableW = - observable.switchMap { f(it).observable }.k() - - companion object { - fun pure(a: A): ObservableW = - Observable.just(a).k() - - fun raiseError(t: Throwable): ObservableW = - Observable.error(t).k() - - fun runAsync(fa: Proc): ObservableW = - Observable.create { emitter: ObservableEmitter -> - fa { either: Either -> - either.fold({ - emitter.onError(it) - }, { - emitter.onNext(it) - emitter.onComplete() - }) - - } - }.k() - - fun monadFlat(): ObservableWFlatMonadInstance = ObservableWFlatMonadInstanceImplicits.instance() - - fun monadConcat(): ObservableWConcatMonadInstance = ObservableWConcatMonadInstanceImplicits.instance() - - fun monadSwitch(): ObservableWSwitchMonadInstance = ObservableWSwitchMonadInstanceImplicits.instance() - - fun monadErrorFlat(): ObservableWFlatMonadErrorInstance = ObservableWFlatMonadErrorInstanceImplicits.instance() - - fun monadErrorConcat(): ObservableWConcatMonadErrorInstance = ObservableWConcatMonadErrorInstanceImplicits.instance() - - fun monadErrorSwitch(): ObservableWSwitchMonadErrorInstance = ObservableWSwitchMonadErrorInstanceImplicits.instance() - } -} - -fun ObservableW.handleErrorWith(function: (Throwable) -> ObservableW): ObservableW = - this.observable.onErrorResumeNext { t: Throwable -> function(t).observable }.k() \ No newline at end of file diff --git a/kategory-effects-rx2/src/main/kotlin/kategory/effects/instances/ObservableWInstances.kt b/kategory-effects-rx2/src/main/kotlin/kategory/effects/instances/ObservableWInstances.kt index d1f347b77bf..c73a1a4ac42 100644 --- a/kategory-effects-rx2/src/main/kotlin/kategory/effects/instances/ObservableWInstances.kt +++ b/kategory-effects-rx2/src/main/kotlin/kategory/effects/instances/ObservableWInstances.kt @@ -1,117 +1,117 @@ package kategory -object ObservableWMonadInstanceImplicits { +object ObservableKWMonadInstanceImplicits { @JvmStatic - fun instance(): ObservableWFlatMonadInstance = ObservableWFlatMonadInstanceImplicits.instance() + fun instance(): ObservableKWFlatMonadInstance = ObservableKWFlatMonadInstanceImplicits.instance() } -object ObservableWMonadErrorInstanceImplicits { +object ObservableKWMonadErrorInstanceImplicits { @JvmStatic - fun instance(): ObservableWFlatMonadErrorInstance = ObservableWFlatMonadErrorInstanceImplicits.instance() + fun instance(): ObservableKWFlatMonadErrorInstance = ObservableKWFlatMonadErrorInstanceImplicits.instance() } -interface ObservableWFlatMonadInstance : - ObservableWApplicativeInstance, - Monad { - override fun ap(fa: ObservableWKind, ff: ObservableWKind<(A) -> B>): ObservableW = +interface ObservableKWFlatMonadInstance : + ObservableKWApplicativeInstance, + Monad { + override fun ap(fa: ObservableKWKind, ff: ObservableKWKind<(A) -> B>): ObservableKW = fa.ev().ap(ff) - override fun flatMap(fa: ObservableWKind, f: (A) -> ObservableWKind): ObservableWKind = + override fun flatMap(fa: ObservableKWKind, f: (A) -> ObservableKWKind): ObservableKWKind = fa.ev().flatMap { f(it).ev() } - override fun tailRecM(a: A, f: (A) -> ObservableWKind>): ObservableWKind = + override fun tailRecM(a: A, f: (A) -> ObservableKWKind>): ObservableKWKind = f(a).ev().flatMap { it.fold({ tailRecM(a, f).ev() }, { pure(it).ev() }) } } -object ObservableWFlatMonadInstanceImplicits { +object ObservableKWFlatMonadInstanceImplicits { @JvmStatic - fun instance(): ObservableWFlatMonadInstance = object : ObservableWFlatMonadInstance {} + fun instance(): ObservableKWFlatMonadInstance = object : ObservableKWFlatMonadInstance {} } -interface ObservableWFlatMonadErrorInstance : - ObservableWFlatMonadInstance, - MonadError { - override fun raiseError(e: Throwable): ObservableW = - ObservableW.raiseError(e) +interface ObservableKWFlatMonadErrorInstance : + ObservableKWFlatMonadInstance, + MonadError { + override fun raiseError(e: Throwable): ObservableKW = + ObservableKW.raiseError(e) - override fun handleErrorWith(fa: ObservableWKind, f: (Throwable) -> ObservableWKind): ObservableW = + override fun handleErrorWith(fa: ObservableKWKind, f: (Throwable) -> ObservableKWKind): ObservableKW = fa.ev().handleErrorWith { f(it).ev() } } -object ObservableWFlatMonadErrorInstanceImplicits { +object ObservableKWFlatMonadErrorInstanceImplicits { @JvmStatic - fun instance(): ObservableWFlatMonadErrorInstance = object : ObservableWFlatMonadErrorInstance {} + fun instance(): ObservableKWFlatMonadErrorInstance = object : ObservableKWFlatMonadErrorInstance {} } -interface ObservableWConcatMonadInstance : - ObservableWApplicativeInstance, - Monad { - override fun ap(fa: ObservableWKind, ff: ObservableWKind<(A) -> B>): ObservableW = +interface ObservableKWConcatMonadInstance : + ObservableKWApplicativeInstance, + Monad { + override fun ap(fa: ObservableKWKind, ff: ObservableKWKind<(A) -> B>): ObservableKW = fa.ev().ap(ff) - override fun flatMap(fa: ObservableWKind, f: (A) -> ObservableWKind): ObservableW = + override fun flatMap(fa: ObservableKWKind, f: (A) -> ObservableKWKind): ObservableKW = fa.ev().concatMap { f(it).ev() } - override fun tailRecM(a: A, f: (A) -> ObservableWKind>): ObservableW = + override fun tailRecM(a: A, f: (A) -> ObservableKWKind>): ObservableKW = f(a).ev().concatMap { it.fold({ tailRecM(a, f).ev() }, { pure(it).ev() }) } } -object ObservableWConcatMonadInstanceImplicits { +object ObservableKWConcatMonadInstanceImplicits { @JvmStatic - fun instance(): ObservableWConcatMonadInstance = object : ObservableWConcatMonadInstance {} + fun instance(): ObservableKWConcatMonadInstance = object : ObservableKWConcatMonadInstance {} } -interface ObservableWConcatMonadErrorInstance : - ObservableWConcatMonadInstance, - MonadError { - override fun raiseError(e: Throwable): ObservableW = - ObservableW.raiseError(e) +interface ObservableKWConcatMonadErrorInstance : + ObservableKWConcatMonadInstance, + MonadError { + override fun raiseError(e: Throwable): ObservableKW = + ObservableKW.raiseError(e) - override fun handleErrorWith(fa: ObservableWKind, f: (Throwable) -> ObservableWKind): ObservableW = + override fun handleErrorWith(fa: ObservableKWKind, f: (Throwable) -> ObservableKWKind): ObservableKW = fa.ev().handleErrorWith { f(it).ev() } } -object ObservableWConcatMonadErrorInstanceImplicits { +object ObservableKWConcatMonadErrorInstanceImplicits { @JvmStatic - fun instance(): ObservableWConcatMonadErrorInstance = object : ObservableWConcatMonadErrorInstance {} + fun instance(): ObservableKWConcatMonadErrorInstance = object : ObservableKWConcatMonadErrorInstance {} } -interface ObservableWSwitchMonadInstance : - ObservableWApplicativeInstance, - Monad { - override fun ap(fa: ObservableWKind, ff: ObservableWKind<(A) -> B>): ObservableW = +interface ObservableKWSwitchMonadInstance : + ObservableKWApplicativeInstance, + Monad { + override fun ap(fa: ObservableKWKind, ff: ObservableKWKind<(A) -> B>): ObservableKW = fa.ev().ap(ff) - override fun flatMap(fa: ObservableWKind, f: (A) -> ObservableWKind): ObservableW = + override fun flatMap(fa: ObservableKWKind, f: (A) -> ObservableKWKind): ObservableKW = fa.ev().switchMap { f(it).ev() } - override fun tailRecM(a: A, f: (A) -> ObservableWKind>): ObservableW = + override fun tailRecM(a: A, f: (A) -> ObservableKWKind>): ObservableKW = f(a).ev().switchMap { it.fold({ tailRecM(a, f).ev() }, { pure(it).ev() }) } } -object ObservableWSwitchMonadInstanceImplicits { +object ObservableKWSwitchMonadInstanceImplicits { @JvmStatic - fun instance(): ObservableWSwitchMonadInstance = object : ObservableWSwitchMonadInstance {} + fun instance(): ObservableKWSwitchMonadInstance = object : ObservableKWSwitchMonadInstance {} } -interface ObservableWSwitchMonadErrorInstance : - ObservableWSwitchMonadInstance, - MonadError { +interface ObservableKWSwitchMonadErrorInstance : + ObservableKWSwitchMonadInstance, + MonadError { - override fun raiseError(e: Throwable): ObservableW = - ObservableW.raiseError(e) + override fun raiseError(e: Throwable): ObservableKW = + ObservableKW.raiseError(e) - override fun handleErrorWith(fa: ObservableWKind, f: (Throwable) -> ObservableWKind): ObservableW = + override fun handleErrorWith(fa: ObservableKWKind, f: (Throwable) -> ObservableKWKind): ObservableKW = fa.ev().handleErrorWith { f(it).ev() } } -object ObservableWSwitchMonadErrorInstanceImplicits { +object ObservableKWSwitchMonadErrorInstanceImplicits { @JvmStatic - fun instance(): ObservableWSwitchMonadErrorInstance = object : ObservableWSwitchMonadErrorInstance {} + fun instance(): ObservableKWSwitchMonadErrorInstance = object : ObservableKWSwitchMonadErrorInstance {} } \ No newline at end of file diff --git a/kategory-effects-rx2/src/test/kotlin/kategory/effects/data/ObservableWTests.kt b/kategory-effects-rx2/src/test/kotlin/kategory/effects/data/ObservableWTests.kt index 8b8ca83b93a..c8bee9cc4b0 100644 --- a/kategory-effects-rx2/src/test/kotlin/kategory/effects/data/ObservableWTests.kt +++ b/kategory-effects-rx2/src/test/kotlin/kategory/effects/data/ObservableWTests.kt @@ -10,10 +10,10 @@ import org.junit.runner.RunWith import java.util.concurrent.TimeUnit @RunWith(KTestJUnitRunner::class) -class ObservableWTest : UnitSpec() { +class ObservableKWTest : UnitSpec() { - fun EQ(): Eq> = object : Eq> { - override fun eqv(a: ObservableWKind, b: ObservableWKind): Boolean = + fun EQ(): Eq> = object : Eq> { + override fun eqv(a: ObservableKWKind, b: ObservableKWKind): Boolean = try { a.value().blockingFirst() == b.value().blockingFirst() } catch (throwable: Throwable) { @@ -38,19 +38,19 @@ class ObservableWTest : UnitSpec() { init { "instances can be resolved implicitly" { - functor() shouldNotBe null - applicative() shouldNotBe null - monad() shouldNotBe null - monadError() shouldNotBe null - asyncContext() shouldNotBe null + functor() shouldNotBe null + applicative() shouldNotBe null + monad() shouldNotBe null + monadError() shouldNotBe null + asyncContext() shouldNotBe null } - testLaws(AsyncLaws.laws(ObservableW.asyncContext(), ObservableW.monadErrorFlat(), EQ(), EQ())) - testLaws(AsyncLaws.laws(ObservableW.asyncContext(), ObservableW.monadErrorConcat(), EQ(), EQ())) - testLaws(AsyncLaws.laws(ObservableW.asyncContext(), ObservableW.monadErrorSwitch(), EQ(), EQ())) + testLaws(AsyncLaws.laws(ObservableKW.asyncContext(), ObservableKW.monadErrorFlat(), EQ(), EQ())) + testLaws(AsyncLaws.laws(ObservableKW.asyncContext(), ObservableKW.monadErrorConcat(), EQ(), EQ())) + testLaws(AsyncLaws.laws(ObservableKW.asyncContext(), ObservableKW.monadErrorSwitch(), EQ(), EQ())) "Multi-thread Observables finish correctly" { - val value: Observable = ObservableW.monadErrorFlat().bindingE { + val value: Observable = ObservableKW.monadErrorFlat().bindingE { val a = Observable.timer(2, TimeUnit.SECONDS).k().bind() yields(a) }.value() @@ -63,7 +63,7 @@ class ObservableWTest : UnitSpec() { "Multi-thread Observables should run on their required threads" { val originalThread: Thread = Thread.currentThread() var nextThread: Thread? = null - val value: Observable = ObservableW.monadErrorFlat().bindingE { + val value: Observable = ObservableKW.monadErrorFlat().bindingE { val a = Observable.timer(2, TimeUnit.SECONDS).k().bind() nextThread = Thread.currentThread() val b = Observable.just(a).observeOn(Schedulers.io()).k().bind() @@ -77,7 +77,7 @@ class ObservableWTest : UnitSpec() { } "Observable cancellation forces binding to cancel without completing too" { - val value: Observable = ObservableW.monadErrorFlat().bindingE { + val value: Observable = ObservableKW.monadErrorFlat().bindingE { val a = Observable.timer(3, TimeUnit.SECONDS).k().bind() yields(a) }.value()