скала кошки неоднозначные скрытые ценности - PullRequest
0 голосов
/ 04 февраля 2019
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 голосов
/ 04 февраля 2019

Проблема в том, что вы слишком много спрашиваете о типах 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 получалась десагаредированной к неявному параметру Monad[F], которыйдошел до C: Console[F] в списке неявных параметров, и поэтому компилятор сначала пытался разрешить его.В вышеприведенной версии без сахара я изменил порядок, чтобы он сначала разрешил Console[F], что заставит все работать нормально, когда компилятор попытается вывести F для вызовов doFoo(number).

...