Skip to content

Commit 492716f

Browse files
committed
Add Scalaz & Cats instances for AsyncCallback
1 parent 69857d7 commit 492716f

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

cats/src/main/scala/japgolly/scalajs/react/internal/CatsReactInstances.scala

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import japgolly.scalajs.react.extra._
99
trait CatsReactInstances {
1010

1111
implicit final lazy val reactCallbackCatsInstance: MonadError[CallbackTo, Throwable] = new MonadError[CallbackTo, Throwable] {
12-
override def pure[A](x: A): CallbackTo[A] = CallbackTo.pure(x)
12+
override def pure[A](x: A): CallbackTo[A] =
13+
CallbackTo.pure(x)
1314

1415
override def map[A, B](fa: CallbackTo[A])(f: A => B): CallbackTo[B] =
1516
fa.map(f)
@@ -30,6 +31,39 @@ trait CatsReactInstances {
3031
}
3132
}
3233

34+
implicit final lazy val reactAsyncCallbackCatsInstance: MonadError[AsyncCallback, Throwable] = new MonadError[AsyncCallback, Throwable] {
35+
36+
override def pure[A](x: A): AsyncCallback[A] =
37+
AsyncCallback.pure(x)
38+
39+
override def ap[A, B](ff: AsyncCallback[A => B])(fa: AsyncCallback[A]) =
40+
ff.zipWith(fa)(_(_))
41+
42+
override def ap2[A, B, Z](ff: AsyncCallback[(A, B) => Z])(fa: AsyncCallback[A], fb: AsyncCallback[B]) =
43+
ff.zipWith(fa.zip(fb))(_.tupled(_))
44+
45+
override def map2[A, B, Z](fa: AsyncCallback[A], fb: AsyncCallback[B])(f: (A, B) => Z) =
46+
fa.zipWith(fb)(f)
47+
48+
override def map[A, B](fa: AsyncCallback[A])(f: A => B): AsyncCallback[B] =
49+
fa.map(f)
50+
51+
override def flatMap[A, B](fa: AsyncCallback[A])(f: A => AsyncCallback[B]): AsyncCallback[B] =
52+
fa.flatMap(f)
53+
54+
override def tailRecM[A, B](a: A)(f: A => AsyncCallback[Either[A, B]]): AsyncCallback[B] =
55+
AsyncCallback.tailrec(a)(f)
56+
57+
override def raiseError[A](e: Throwable): AsyncCallback[A] =
58+
AsyncCallback(throw e)
59+
60+
override def handleErrorWith[A](fa: AsyncCallback[A])(f: Throwable => AsyncCallback[A]): AsyncCallback[A] =
61+
fa.attempt.flatMap {
62+
case Right(a) => AsyncCallback pure a
63+
case Left(t) => f(t)
64+
}
65+
}
66+
3367
implicit final lazy val reactCallbackOptionCatsInstance: Monad[CallbackOption] = new Monad[CallbackOption] {
3468
override def pure[A](x: A): CallbackOption[A] = CallbackOption.pure(x)
3569

core/src/main/scala/japgolly/scalajs/react/AsyncCallback.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ object AsyncCallback {
113113

114114
@inline implicit def asynCallbackCovariance[A, B >: A](c: AsyncCallback[A]): AsyncCallback[B] =
115115
c.widen
116+
117+
/** Not literally tail-recursive because AsyncCallback is continuation-based, but this utility in this shape may still
118+
* be useful.
119+
*/
120+
def tailrec[A, B](a: A)(f: A => AsyncCallback[Either[A, B]]): AsyncCallback[B] =
121+
f(a).flatMap {
122+
case Left(a2) => tailrec(a2)(f)
123+
case Right(b) => pure(b)
124+
}
116125
}
117126

118127
/** Pure asynchronous callback.

scalaz-7.2/src/main/scala/japgolly/scalajs/react/internal/ScalazReactInstances.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,40 @@ trait ScalazReactInstances {
3838
}
3939
}
4040

41+
implicit final lazy val reactAsyncCallbackScalazInstance: MonadError[AsyncCallback, Throwable] with BindRec[AsyncCallback] =
42+
new MonadError[AsyncCallback, Throwable] with BindRec[AsyncCallback] {
43+
44+
override def point[A](a: => A): AsyncCallback[A] =
45+
AsyncCallback.point(a)
46+
47+
override def ap[A, B](fa: => AsyncCallback[A])(f: => AsyncCallback[A => B]) =
48+
f.zipWith(fa)(_(_))
49+
50+
override def ap2[A, B, C](fa: => AsyncCallback[A], fb: => AsyncCallback[B])(f: AsyncCallback[(A, B) => C]) =
51+
f.zipWith(fa.zip(fb))(_.tupled(_))
52+
53+
override def apply2[A, B, C](fa: => AsyncCallback[A], fb: => AsyncCallback[B])(f: (A, B) => C) =
54+
fa.zipWith(fb)(f)
55+
56+
override def bind[A, B](fa: AsyncCallback[A])(f: A => AsyncCallback[B]): AsyncCallback[B] =
57+
fa >>= f
58+
59+
override def map[A, B](fa : AsyncCallback[A])(f : A => B): AsyncCallback[B] =
60+
fa map f
61+
62+
override def tailrecM[A, B](f: A => AsyncCallback[A \/ B])(a: A): AsyncCallback[B] =
63+
AsyncCallback.tailrec(a)(f.andThen(_.map(_.toEither)))
64+
65+
override def raiseError[A](e: Throwable): AsyncCallback[A] =
66+
AsyncCallback.throwException(e)
67+
68+
override def handleError[A](fa: AsyncCallback[A])(f: Throwable => AsyncCallback[A]): AsyncCallback[A] =
69+
fa.attempt.flatMap {
70+
case Right(a) => AsyncCallback pure a
71+
case Left(t) => f(t)
72+
}
73+
}
74+
4175
implicit final lazy val reactCallbackOptionScalazInstance: MonadPlus[CallbackOption] with BindRec[CallbackOption] =
4276
new MonadPlus[CallbackOption] with BindRec[CallbackOption] {
4377
override def point[A](a: => A): CallbackOption[A] =

0 commit comments

Comments
 (0)