Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala FlatMap and Applicative context boundaries yield compile error

I'm doing some staff in Scala and came across a problem with implicit instances. Let's consider the following example:

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 ()
}

This compiles fine. But since cats.Monad[F[_]] is declared as follows:

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

I expected the following to work as well

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 ()
}

But it fails to compile with error:

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

This is strange. Apply extends Functor...

Can anyone explain this behavior?

like image 551
St.Antario Avatar asked Dec 21 '25 09:12

St.Antario


1 Answers

class Test[F[_] : FlatMap : Applicative] is desugared to

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

If you desugar for-comprehension and syntaxes you'll see the problem:

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]

So you can resolve ambiguity manually:

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

or

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

There is no such problem when you write class Test[F[_]: Monad] since you have single implicit.

like image 111
Dmytro Mitin Avatar answered Dec 24 '25 02:12

Dmytro Mitin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!