斯卡拉猫模棱两可的隐含价值
scala cats ambiguous implicit values
import cats._
import cats.implicits._
trait Console[F[_]]{
def readInput() : F[Int]
def print(msg: String) : F[Unit]
}
class Foo {
def doFoo[F[_]: Monad](number: Int)(implicit C: Console[F]) : F[Unit] = {
C.readInput().flatMap{input =>
if (input == number) C.print("you won").map(_ => ())
else if (input > number) C.print("you guessed too high").flatMap(_ => doFoo(number))
else C.print("you guessed too low").flatMap(_ => doFoo(number))
}
}
}
但是我从编译器那里得到了这个神秘的错误
cmd18.sc:5: ambiguous implicit values:
both value catsStdInstancesForList in trait ListInstances of type => cats.Traverse[List] with cats.Alternative[List] with cats.Monad[List] with cats.CoflatMap[List]
and value catsStdInstancesForVector in trait VectorInstances of type => cats.Traverse[Vector] with cats.Monad[Vector] with cats.Alternative[Vector] with cats.CoflatMap[Vector]
match expected type cats.Monad[F]
else if (input > number) C.print("you guessed too high").flatMap(_ => dooFoo(number))
^
问题是您对 Scala 的类型推断要求过多。它试图找出 doFoo[?](number)
所需的类型参数,虽然我们人类很清楚它必须是 F
给定表达式 doFoo(number)
出现的上下文,编译器没那么聪明。
最简单的解决方案就是明确提供类型参数:
.flatMap(_ => doFoo[F](number))
如果你觉得这很烦人,你可以通过去除 F[_]: Monad
约束绑定的糖来帮助编译器,这样你就可以确定 Console
和 Monad
实例的顺序显式:
import cats._
import cats.implicits._
trait Console[F[_]]{
def readInput() : F[Int]
def print(msg: String) : F[Unit]
}
class Foo {
def doFoo[F[_]](number: Int)(implicit C: Console[F], F: Monad[F]) : F[Unit] = {
C.readInput().flatMap{input =>
if (input == number) C.print("you won").map(_ => ())
else if (input > number) C.print("you guessed too high").flatMap(_ => doFoo(number))
else C.print("you guessed too low").flatMap(_ => doFoo(number))
}
}
}
在您的原始版本中,Monad
上下文绑定被脱糖为隐式参数列表中 C: Console[F]
之前的隐式 Monad[F]
参数,因此编译器正在尝试先解决它。在上面的无糖版本中,我颠倒了顺序,以便它首先解析 Console[F]
,这将使编译器开始尝试推断 F
时一切正常doFoo(number)
次调用。
import cats._
import cats.implicits._
trait Console[F[_]]{
def readInput() : F[Int]
def print(msg: String) : F[Unit]
}
class Foo {
def doFoo[F[_]: Monad](number: Int)(implicit C: Console[F]) : F[Unit] = {
C.readInput().flatMap{input =>
if (input == number) C.print("you won").map(_ => ())
else if (input > number) C.print("you guessed too high").flatMap(_ => doFoo(number))
else C.print("you guessed too low").flatMap(_ => doFoo(number))
}
}
}
但是我从编译器那里得到了这个神秘的错误
cmd18.sc:5: ambiguous implicit values:
both value catsStdInstancesForList in trait ListInstances of type => cats.Traverse[List] with cats.Alternative[List] with cats.Monad[List] with cats.CoflatMap[List]
and value catsStdInstancesForVector in trait VectorInstances of type => cats.Traverse[Vector] with cats.Monad[Vector] with cats.Alternative[Vector] with cats.CoflatMap[Vector]
match expected type cats.Monad[F]
else if (input > number) C.print("you guessed too high").flatMap(_ => dooFoo(number))
^
问题是您对 Scala 的类型推断要求过多。它试图找出 doFoo[?](number)
所需的类型参数,虽然我们人类很清楚它必须是 F
给定表达式 doFoo(number)
出现的上下文,编译器没那么聪明。
最简单的解决方案就是明确提供类型参数:
.flatMap(_ => doFoo[F](number))
如果你觉得这很烦人,你可以通过去除 F[_]: Monad
约束绑定的糖来帮助编译器,这样你就可以确定 Console
和 Monad
实例的顺序显式:
import cats._
import cats.implicits._
trait Console[F[_]]{
def readInput() : F[Int]
def print(msg: String) : F[Unit]
}
class Foo {
def doFoo[F[_]](number: Int)(implicit C: Console[F], F: Monad[F]) : F[Unit] = {
C.readInput().flatMap{input =>
if (input == number) C.print("you won").map(_ => ())
else if (input > number) C.print("you guessed too high").flatMap(_ => doFoo(number))
else C.print("you guessed too low").flatMap(_ => doFoo(number))
}
}
}
在您的原始版本中,Monad
上下文绑定被脱糖为隐式参数列表中 C: Console[F]
之前的隐式 Monad[F]
参数,因此编译器正在尝试先解决它。在上面的无糖版本中,我颠倒了顺序,以便它首先解析 Console[F]
,这将使编译器开始尝试推断 F
时一切正常doFoo(number)
次调用。