Проблема в том, что вы слишком много спрашиваете о типах 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)
.