Skip to content

Commit

Permalink
Added liftR to functions as a workaround for Scala's poor type inference
Browse files Browse the repository at this point in the history
  • Loading branch information
japgolly committed Nov 23, 2014
1 parent d648bb9 commit 088ffad
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 6 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ In addition to React API changes...
* `.toJsArray: Seq[A] → JArray[ReactElement]` is no longer needed.
* Renamed `ComponentSpec` to `ReactComponentSpec`. *(Internal. Extremely unlikely anyone using it directly.)*
* Changed signatures of `ReactS.callback` and brethren from `(c)(a)` to `(a,c)`.
* Workaround for Scala's type inference failing with `StateT.liftR` on functions.
Instead of `f(_).liftR`, `f.liftR` is now available and is confirmed to work in `_runState`.

Here are a few commands to ease migration.
```
Expand Down
6 changes: 4 additions & 2 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ object ScalajsReact extends Build {

lazy val test = project
.configure(commonSettings, publicationSettings, utestSettings)
.dependsOn(core)
.settings(name := "test")
.dependsOn(core, scalaz71)
.settings(
name := "test",
scalacOptions += "-language:reflectiveCalls")

// ==============================================================================================
def scalazModule(name: String, version: String) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ object ScalazReact {
ReactS lift s
}

implicit final class SzRExt__StateTOps[I, M[+_], S, A](val f: I => StateT[M, S, A]) extends AnyVal {
@inline def liftR(implicit M: Functor[M]): I => ReactST[M, S, A] =
f(_).liftR
}

implicit final class SzRExt_ReactSTOps[M[+_], S, A](val s: ReactST[M,S,A]) extends AnyVal {
def addCallback(c: OpCallbackIO)(implicit M: Monad[M]): ReactST[M,S,A] =
s.flatMap(ReactS.callbackT(_, c))
Expand Down Expand Up @@ -216,7 +221,7 @@ object ScalazReact {
def runStateS[M[+_], A](st: => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M]): IO[A] =
runState(st.liftR)

@deprecated("Instead of _runStateS(i ⇒ s | f), use _runState(i ⇒ s.liftR | f(_).liftR). _runStateS will be removed in 0.7.0.", "0.5.2")
@deprecated("Instead of _runStateS(f), use _runState(f.liftR). _runStateS will be removed in 0.7.0.", "0.5.2")
def _runStateS[I, M[+_], A](f: I => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M]): I => IO[A] =
_runState(f(_).liftR)

Expand All @@ -233,7 +238,7 @@ object ScalazReact {
def runStateFS[M[+_], A](st: => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M], F: ChangeFilter[S]): IO[A] =
runStateF(st.liftR)

@deprecated("Instead of _runStateFS(i ⇒ s | f), use _runStateF(i ⇒ s.liftR | f(_).liftR). _runStateFS will be removed in 0.7.0.", "0.5.2")
@deprecated("Instead of _runStateFS(f), use _runStateF(f.liftR). _runStateFS will be removed in 0.7.0.", "0.5.2")
def _runStateFS[I, M[+_], A](f: I => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M], F: ChangeFilter[S]): I => IO[A] =
_runStateF(f(_).liftR)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ object ScalazReact {
ReactS lift s
}

implicit final class SzRExt__StateTOps[I, M[_], S, A](val f: I => StateT[M, S, A]) extends AnyVal {
@inline def liftR(implicit M: Functor[M]): I => ReactST[M, S, A] =
f(_).liftR
}

implicit final class SzRExt_ReactSTOps[M[_], S, A](val s: ReactST[M,S,A]) extends AnyVal {
def addCallback(c: OpCallbackIO)(implicit M: Monad[M]): ReactST[M,S,A] =
s.flatMap(ReactS.callbackT(_, c))
Expand Down Expand Up @@ -215,7 +220,7 @@ object ScalazReact {
def runStateS[M[_], A](st: => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M]): IO[A] =
runState(st.liftR)

@deprecated("Instead of _runStateS(i ⇒ s | f), use _runState(i ⇒ s.liftR | f(_).liftR). _runStateS will be removed in 0.7.0.", "0.5.2")
@deprecated("Instead of _runStateS(f), use _runState(f.liftR). _runStateS will be removed in 0.7.0.", "0.5.2")
def _runStateS[I, M[_], A](f: I => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M]): I => IO[A] =
_runState(f(_).liftR)

Expand All @@ -232,7 +237,7 @@ object ScalazReact {
def runStateFS[M[_], A](st: => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M], F: ChangeFilter[S]): IO[A] =
runStateF(st.liftR)

@deprecated("Instead of _runStateFS(i ⇒ s | f), use _runStateF(i ⇒ s.liftR | f(_).liftR). _runStateFS will be removed in 0.7.0.", "0.5.2")
@deprecated("Instead of _runStateFS(f), use _runStateF(f.liftR). _runStateFS will be removed in 0.7.0.", "0.5.2")
def _runStateFS[I, M[_], A](f: I => StateT[M, S, A])(implicit C: CC, M: M ~> IO, N: Functor[M], F: ChangeFilter[S]): I => IO[A] =
_runStateF(f(_).liftR)
}
Expand Down
31 changes: 31 additions & 0 deletions test/src/test/scala/japgolly/scalajs/react/ScalazTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package japgolly.scalajs.react

import utest._
import scalaz.{~>, StateT, Monad}
import scalaz.effect.IO
import ScalazReact._

/**
* Scala's type inference can be pretty weak sometimes.
* Successful compilation will suffice as proof for most of these tests.
*/
object ScalazTest extends TestSuite {

def test[A] = new {
def apply[B](f: A => B) = new {
def expect[C](implicit ev: B =:= C): Unit = ()
}
}

trait M[A]
implicit val mMonad = null.asInstanceOf[Monad[M] with (M ~> IO)]
trait S
trait A
trait B
val c = null.asInstanceOf[ComponentScopeM[Unit, S, Unit]]

val tests = TestSuite {
"runState(StateT.liftR)" - test[StateT[M,S,A] ](s => c.runState(s.liftR) ).expect[IO[A]]
"_runState((I→StateT).liftR)" - test[B => StateT[M,S,A]](s => c._runState(s.liftR)).expect[B => IO[A]]
}
}

0 comments on commit 088ffad

Please sign in to comment.