Option[io.databaker.env.EnvValue],但类型F在类型上是不变的
Option[io.databaker.env.EnvValue], but type F is invariant in type
我有以下代码片段,它没有被编译:
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]
}
编译器抱怨:
[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]
我做错了什么?
这里是问题的最小化示例,显示了引入 pure
扩展方法的导入:
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)
问题是 None.pure[F]
的类型被推断为 F[None.type]
,而没有预期的 return 类型影响推断。如果你 desugar 上下文绑定和扩展方法,类型推断将按你预期的那样工作:
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]]
你也可以写出 Option.empty[String].pure[F]
之类的东西——有很多方法可以 运行 解决这种问题(过于精确的类型推断),还有很多解决它的方法,你应该选择哪种主要是品味问题。
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?
考虑 F
这个名字在 implicit F: Applicative[F]
中的使用方式
def foo[F[_]](implicit F: Applicative[F]): F[Option[String]] = F.pure(None)
| | | |
type value type "type as value"
请注意 value 参数 F
如何与 type[=61] 具有 相同 名称=]参数F
。现在在值 F
上调用方法看起来就像我们在类型
上调用方法一样
F.pure(None)
在 Scala 中使用点语法调用类型上的方法是不可能的,但从概念上讲这就是我们正在做的事情——我们希望传达调用“类型级”函数的想法。 naming convention 之所以有效,是因为值和类型存在于两个独立的宇宙中,因此我们可以重复使用相同的名称而不会发生冲突。例如,考虑为什么以下是合法的
scala> object f { def f[f](f: f): f = f }
| val Int: Int = 42
object f
val Int: Int = 42
现在使用上下文绑定 :
表示法
def foo[F[_]: Applicative]: F[Option[String]] = Applicative[F].pure(None)
我们没有隐式值参数的名称可以使用,所以我们不能使用上面的约定技巧和调用
F.pure(None)
再一次,因为类型上的点符号严格来说是非法的,所以我们改为使用带有 main 方法技巧的伴随对象
Applicative[F].pure(None)
这是可行的,因为 Applicative
伴侣有类似
的内容
Applicative {
def apply[F[_]](implicit instance: Applicative[F]): Applicative[F] = instance
}
所以打电话
Applicative.apply[F]
或更短
Applicative[F]
returns 范围内的隐式 instance
。在这一点上,我们确实有我们的 value 可以使用,所以点符号变得合法
Applicative[F].pure(None)
|
ok because invoked on a value
因此,您必须使用 Sync[F].pure(None)
而不是 F.pure(None)
进行调用,因为在您的特定情况下,您使用的是上下文边界。
我有以下代码片段,它没有被编译:
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]
}
编译器抱怨:
[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]
我做错了什么?
这里是问题的最小化示例,显示了引入 pure
扩展方法的导入:
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)
问题是 None.pure[F]
的类型被推断为 F[None.type]
,而没有预期的 return 类型影响推断。如果你 desugar 上下文绑定和扩展方法,类型推断将按你预期的那样工作:
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]]
你也可以写出 Option.empty[String].pure[F]
之类的东西——有很多方法可以 运行 解决这种问题(过于精确的类型推断),还有很多解决它的方法,你应该选择哪种主要是品味问题。
I have changed to override
def get(v: env.EnvVariable): F[Option[env.EnvValue]] = F.pure(None)
and got the error messagenot found: value F
. What am I doing wrong?
考虑 F
这个名字在 implicit F: Applicative[F]
def foo[F[_]](implicit F: Applicative[F]): F[Option[String]] = F.pure(None)
| | | |
type value type "type as value"
请注意 value 参数 F
如何与 type[=61] 具有 相同 名称=]参数F
。现在在值 F
上调用方法看起来就像我们在类型
F.pure(None)
在 Scala 中使用点语法调用类型上的方法是不可能的,但从概念上讲这就是我们正在做的事情——我们希望传达调用“类型级”函数的想法。 naming convention 之所以有效,是因为值和类型存在于两个独立的宇宙中,因此我们可以重复使用相同的名称而不会发生冲突。例如,考虑为什么以下是合法的
scala> object f { def f[f](f: f): f = f }
| val Int: Int = 42
object f
val Int: Int = 42
现在使用上下文绑定 :
表示法
def foo[F[_]: Applicative]: F[Option[String]] = Applicative[F].pure(None)
我们没有隐式值参数的名称可以使用,所以我们不能使用上面的约定技巧和调用
F.pure(None)
再一次,因为类型上的点符号严格来说是非法的,所以我们改为使用带有 main 方法技巧的伴随对象
Applicative[F].pure(None)
这是可行的,因为 Applicative
伴侣有类似
Applicative {
def apply[F[_]](implicit instance: Applicative[F]): Applicative[F] = instance
}
所以打电话
Applicative.apply[F]
或更短
Applicative[F]
returns 范围内的隐式 instance
。在这一点上,我们确实有我们的 value 可以使用,所以点符号变得合法
Applicative[F].pure(None)
|
ok because invoked on a value
因此,您必须使用 Sync[F].pure(None)
而不是 F.pure(None)
进行调用,因为在您的特定情况下,您使用的是上下文边界。