Reputation: 2557
I've been playing around with Scalaz to get a little bit of the haskell feeling into scala. To understand how things work in scala I started implementing various algebraic structures myself and came across a behavior that has been mentioned by the Scalaz folks.
Here is my example code which implements a functor:
trait Functor[M[_]] {
def fmap[A, B](a: M[A], b: A => B): M[B]
}
sealed abstract class Foo[+A]
case class Bar[A]() extends Foo[A]
case class Baz[A]() extends Foo[A]
object Functor {
implicit val optionFunctor: Functor[Option] = new Functor[Option]{
def fmap[A, B](a: Option[A], b: A => B): Option[B] = a match {
case Some(x) => Some(b(x))
case None => None
}
}
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def fmap[A, B](a: Foo[A], b: A => B): Foo[B] = a match {
case Bar() => Bar()
case Baz() => Baz()
}
}
}
object Main {
import Functor._
def some[A](a: A): Option[A] = Some(a)
def none[A]: Option[A] = None
def fmap[M[_], A, B](a: M[A])(b: A => B)(implicit f: Functor[M]): M[B] =
f.fmap(a, b)
def main(args: Array[String]): Unit = {
println(fmap (some(1))(_ + 1))
println(fmap (none)((_: Int) + 1))
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
}
}
I wrote a functor instance for Option and a bogus sumtype Foo. The problem is that scala cannot infer the implicit parameter without an explicit type annotation or a wrapper method
def some[A](a: A): Option[A] = Some(a)
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
Scala infers types like Functor[Bar] and Functor[Some] without those workarounds.
Why is that? Could anyone please point me to the section in the language spec that defines this behavior?
Regards, raichoo
Upvotes: 2
Views: 944
Reputation: 55028
You're asking the compiler to perform two tasks: local type inference (§6.26.4) of the type arguments to fmap
, and an implicit search for implicit parameter (§7.2) f
. References are to the Scala Reference.
Things go in roughly this order:
fmap[M = ?, A = ?, B = ?](Some(1))(x => x)
// type the arguments of the first parameter section. This is done
// without an expected type, as `M` and `A` are undetermined.
fmap[M = ?, A = ?, B = ?](Some(1): Some[Int])(x => x)(?)
// local type inference determines `M` and `A`
fmap[Some, Int, B = ?](Some(1): Some[Int])(x => x)(?)
// move to the second parameter section, type the argument with the expected type
// `Function1[Int, ?]`. The argument has the type `Function1[Int, Int]`
fmap[Some, Int, ?](Some(1): Some[Int])((x: Int) => x)
// local type inference determines that B = Int
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)
// search local identifiers, and failing that the implicit scope of type `Functor[Some]]`, for an implicit
// value that conforms to `Functor[Some]`
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)(implicitly[Functor[Some]])
The implicit search for Functor[Some]
fails; Functor[Option]
doesn't conform.
Upvotes: 6