【问题标题】:scala cats ambiguous implicit valuesscala 猫模棱两可的隐含值
【发布时间】:2019-02-04 16:24:55
【问题描述】:
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 scala-cats cats-effect


    【解决方案1】:

    问题在于您对 Scala 的类型推断提出了太多要求。它试图找出 doFoo[?](number) 所需的类型参数,虽然对于我们人类来说很清楚它必须是 F 给定表达式 doFoo(number) 出现的上下文,但编译器并不那么聪明.

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

    .flatMap(_ => doFoo[F](number))
    

    如果您觉得这很烦人,您可以通过对 F[_]: Monad 约束绑定进行脱糖来帮助编译器,这样您就可以明确 ConsoleMonad 实例的顺序:

    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],这将使编译器尝试为doFoo(number) 调用推断F 时一切正常.

    【讨论】:

    • 非常感谢。我也能够做到def play[F[_]: Random: Console: Monad]() : F[Unit] = { 编译良好,而无需在调用 doFoo 时明确指定 F。
    • 是的,这对同样的事情很不利。我自己的偏好是在顺序很重要时写出论点,但这是个人喜好问题。
    猜你喜欢
    • 1970-01-01
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多