斯卡拉猫歧义隐含值

时间:2019-02-04 05:08:10

标签: scala scala-cats cats-effect

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))
                                                                        ^

1 个答案:

答案 0 :(得分:13)

问题在于您要问太多Scala的类型推断。它正在尝试找出AccessInfo.businessDate所需的类型参数,而对于人类来说,很明显,给定出现表达式doFoo[?](number)的上下文,它必须是F,编译器不是那么聪明。

最简单的解决方案是显式提供type参数:

doFoo(number)

如果觉得烦人,可以通过取消限制.flatMap(_ => doFoo[F](number)) 约束来帮助编译器,从而使F[_]: MonadConsole实例的顺序明确:

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个呼叫。