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))
^
答案 0 :(得分:13)
问题在于您要问太多Scala的类型推断。它正在尝试找出AccessInfo.businessDate
所需的类型参数,而对于人类来说,很明显,给定出现表达式doFoo[?](number)
的上下文,它必须是F
,编译器不是那么聪明。
最简单的解决方案是显式提供type参数:
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
之前的隐式Monad[F]
参数,因此编译器试图解析首先。在上面的无糖版本中,我颠倒了顺序,以便它可以首先解决C: Console[F]
,这将使所有编译器在尝试推断Console[F]
时都可以正常工作。 F
个呼叫。