I have some code using tagless final approach and found that Intellij IDEA couldn't recognize method from implicit class.
I have some type-classes here (Functor
, Apply
, Applicative
etc.) and one implicit class FunctorOps
with some helper methods for Functor
. This code compiles but IDEA couldn't found void
and implicit Applicative
. Look at the errors:
Cannot resolve symbol void:44
No implicit arguments of type: Applicative[F_]:51
The code looks not too difficult:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(ab: A => B): F[B]
}
trait Semigroupal[F[_]] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}
trait Apply[F[_]] extends Semigroupal[F] with Functor[F] {
def map2[A, B, Result](fa: F[A], fb: F[B])(abr: (A, B) => Result): F[Result] =
map(product(fa, fb))(abr.tupled)
}
trait Applicative[F[_]] extends Apply[F] {
def pure[A](a: A): F[A]
}
object Implicits {
final implicit class FunctorOps[F[_]: Functor, A](private val fa: F[A]) {
@inline def map[B](ab: A => B): F[B] =
F.map(fa)(ab)
@inline def void: F[Unit] =
F.map(fa)(_ => ())
}
}
trait Random[F[_]] {
def nextInt(n: Int): F[Int]
def void: F[Unit]
}
object Random {
import Implicits.FunctorOps
def dsl[F[_]: Applicative]: Random[F] =
new Random[F] {
override def nextInt(n: Int): F[Int] = F.pure(scala.util.Random.nextInt(n))
override def void: F[Unit] = nextInt(4).void
}
}
object Foo {
def dsl[F[_]: Applicative]: F[Unit] =
Random.dsl.void
}
My question: is there any way to avoid this errors in IDEA or it is better to use for example VS Code with Metals or something else? Is there somethign works better with tagless final?
I use std lib and add compiler plugin in sbt for using F
dot method syntax:
addCompilerPlugin("org.augustjune" %% "context-applied" % "0.1.4")
Code with build parameters in scastie
screenshots:
My environment:
Intellij IDEA version 2020.2.3 (with last stable scala plugin)
OS: MacOS Catalina 10.15.7
This behavior fixed in next stable Intellij IDEA version 2020.2.4 and works properly.