bryanph
bryanph

Reputation: 1012

Scala local type inference underscore notation

Working through "Functional programming in Scala", I was wondering why the following code gives a missing parameter type error.

Defined is the following tree data structure:

sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]

And the following methods:

object Tree {

  def fold[A,B](t: Tree[A])(z: A => B)(f: (B,B) => B): B = t match {
    case Leaf(v) => z(v)
    case Branch(l,r) => f(fold(l)(z)(f), fold(r)(z)(f))   }

  def size2[A](t: Tree[A]): Int = fold(t)((_) => 1)(_ + _ + 1)

  def maximum2(t: Tree[Int]): Int = fold(t)((a) => a)(_ max _)

  def depth2[A](t: Tree[A]): Int = fold(t)((_) => 0)(1 + (_ max _))

}

The methods size2 and maximum2 compile just fine, but depth2 does not infer the types on the last function.

Writing the method like:

def depth2[A](t: Tree[A]): Int = fold(t)((_) => 0)((a,b) => 1 + (a max b))

makes it compile just fine.

Q: Why isn't Scala able to infer the type on the first method with the underscore notation, but is on the second method? And what makes the other methods compile just fine?

Thanks for your help.

scalac version: 2.11.4

Upvotes: 0

Views: 121

Answers (2)

Łukasz
Łukasz

Reputation: 8663

1 + (_ max _) expands to 1 + ((a, b) => a max b) which is adding a function to 1. If you specified types you would get another error:

<console>:22: error: overloaded method value + with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int <and>
(x: String)String
cannot be applied to ((Int, Int) => Int)
           def depth2[A](t: Tree[A]): Int = fold(t)((_) => 0)(1 + ((_: Int) max (_: Int)))

as you noticed, you need to put your params explicitly

(a,b) => 1 + (a max b)

or skip parens

1 + _ max _

which you actually can't do here because it would work as if you said

(a,b) => (1 + a) max b

Upvotes: 1

bryanph
bryanph

Reputation: 1012

Turns out, removing the brackets in the first method, removes any compilation errors, like so:

def depth2[A](t: Tree[A]): Int = fold(t)((_) => 0)((a,b) => 1 + a max b)

Hence, it seems that the underscore notation always chooses the closest scope for inferring types.

Upvotes: 0

Related Questions