Option[io.databaker.env.EnvValue], but type F is invariant in type

半城伤御伤魂 提交于 2021-01-27 11:53:45

问题


I have the following code snippet, that does not get compiled:

trait Environment[F[_]] {
  def get(v: EnvVariable): F[Option[EnvValue]]
}

final class LiveBadEnvironment[F[_] : Sync] extends Environment[F] {
  override def get(v: env.EnvVariable): F[Option[env.EnvValue]] = None.pure[F]
}

the compiler complains:

[error]  found   : F[None.type]
[error]  required: F[Option[io.databaker.env.EnvValue]]
[error]     (which expands to)  F[Option[io.databaker.env.EnvValue.Type]]
[error] Note: None.type <: Option[io.databaker.env.EnvValue], but type F is invariant in type _.
[error] You may wish to define _ as +_ instead. (SLS 4.5)
[error]   override def get(v: env.EnvVariable): F[Option[env.EnvValue]] = None.pure[F]

What am I doing wrong?


回答1:


I have changed to override def get(v: env.EnvVariable): F[Option[env.EnvValue]] = F.pure(None) and got the error message not found: value F. What am I doing wrong?

Consider how the name F is used in implicit F: Applicative[F]

def foo[F[_]](implicit F: Applicative[F]): F[Option[String]] = F.pure(None)
        |              |              |                        |
      type           value          type                 "type as value"

Note how the value parameter F has the same name as the type parameter F. Now calling a method on value F looks like as if we are calling a method on a type

F.pure(None)

Invoking a method on a type using dot syntax is not possible in Scala, but conceptually that is what we are doing - we wish to convey the idea of invoking a "type-level" function. This naming convention works because values and types live in two separate universes so we can reuse the same name without clashes. For example, consider why the following is legal

scala> object f { def f[f](f: f): f = f }
     | val Int: Int = 42
object f
val Int: Int = 42              

Now when using context bound : notation

def foo[F[_]: Applicative]: F[Option[String]] = Applicative[F].pure(None)

we do not have the name of implicit value parameter to work with, so we cannot use the above convention trick and call

F.pure(None)

because, again, dot notation on types is strictly speaking illegal, so instead we use the companion object with main method trick

Applicative[F].pure(None)

This works because Applicative companion has something like

Applicative {
  def apply[F[_]](implicit instance: Applicative[F]): Applicative[F] = instance
}

so calling

Applicative.apply[F]

or shorter

Applicative[F]

returns the implicit instance in scope. At this point we do have our value to work with and so dot notation becomes legal

Applicative[F].pure(None)
              |
    ok because invoked on a value

Therefore, you have to call with Sync[F].pure(None) instead of F.pure(None), because in your particular case, you are using context bounds.




回答2:


Here's a minimised example of the issue that shows the import that brings in the pure extension method:

scala> import cats.Applicative, cats.implicits._
import cats.Applicative
import cats.implicits._

scala> def foo[F[_]: Applicative]: F[Option[String]] = None.pure[F]
                                                            ^
   error: type mismatch;
    found   : F[None.type]
    required: F[Option[String]]
   Note: None.type <: Option[String], but type F is invariant in type _.
   You may wish to define _ as +_ instead. (SLS 4.5)

The problem is that the type of None.pure[F] is inferred to be F[None.type], without the expected return type influencing inference. If you desugar the context bound and extension method, type inference will work as you expect:

scala> def foo[F[_]](implicit F: Applicative[F]): F[Option[String]] = F.pure(None)
def foo[F[_]](implicit F: cats.Applicative[F]): F[Option[String]]

You could also write out something like Option.empty[String].pure[F], etc.—there are a lot of ways to run into this kind of issue (too-precise type inference), and a lot of ways to work around it, and which you should choose is mostly a matter of taste.



来源:https://stackoverflow.com/questions/62495683/optionio-databaker-env-envvalue-but-type-f-is-invariant-in-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!