Границы Scala FlatMap и Applicative выдают ошибку компиляции - PullRequest
0 голосов
/ 23 февраля 2019

Я работаю в Scala и столкнулся с проблемой с implicit экземплярами.Давайте рассмотрим следующий пример:

import cats.{Applicative, FlatMap, Monad}
import cats.syntax.functor._
import cats.syntax.flatMap._
import cats.syntax.applicative._


class Test[F[_]: Monad] extends App{
  val t1 = ().pure[F]
  val t2 = ().pure[F]

  def testFlatApplicative: F[Unit] =
    for{
      _ <- t1
      _ <- t2
    } yield ()
}

Это прекрасно скомпилируется.Но так как cats.Monad[F[_]] объявлен следующим образом:

@typeclass trait Monad[F[_]] extends FlatMap[F] with Applicative[F]

Я ожидал, что следующее также будет работать

import cats.{Applicative, FlatMap, Monad}
import cats.syntax.functor._
import cats.syntax.flatMap._
import cats.syntax.applicative._


class Test[F[_]: FlatMap : Applicative] extends App{
  val t1 = ().pure[F]
  val t2 = ().pure[F]

  def testFlatApplicative: F[Unit] =
    for{
      _ <- t1
      _ <- t2
    } yield ()
}

Но он не скомпилируется с ошибкой:

Error:(16, 12) value map is not a member of type parameter F[Unit]
      _ <- t2

Это странно.Apply extends Functor ...

Кто-нибудь может объяснить это поведение?

1 Ответ

0 голосов
/ 23 февраля 2019

class Test[F[_] : FlatMap : Applicative] переведен в

class Test[F[_]](implicit flatMap: FlatMap[F], applicative: Applicative[F])

Если вы разбираетесь в синтаксисе и синтаксисах, вы увидите проблему:

def testFlatApplicative: F[Unit] = 
  FlatMap[F].flatMap(t1)(_ => 
    Functor[F].map(t2)(_ => ())
  )

Error: ambiguous implicit values:
 both value applicative in class Test of type cats.Applicative[F]
 and value flatMap in class Test of type cats.FlatMap[F]
 match expected type cats.Functor[F]

Таким образом, вы можете устранить неоднозначность вручную:

def testFlatApplicative: F[Unit] = 
  FlatMap[F].flatMap(t1)(_ => 
    applicative.map(t2)(_ => ())
  )

или

def testFlatApplicative: F[Unit] = 
  FlatMap[F].flatMap(t1)(_ => 
    flatMap.map(t2)(_ => ())
  )

Когда вы пишете class Test[F[_]: Monad], такой проблемы не возникает, поскольку у вас есть одно неявное значение.

...