Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Generic Function Values (Anonymous Function) - Missing Parameter Type (Error)

I'm new to Scala (Scala code runner version 2.7.7.final), and I really don't understand why it requires the caller to provide the parameter type when we are using high order functions.

In the sample below, I have one stand alone object ( Util ) that has one function. But in the Main block, the caller must pass the parameter type to the anonymous function.

Why does Scala not infer the type of the function from the Array type (i.e. String)? Is there any way to do that ?

object Util {

 // Just for fun! Suppose that the arrayOne and arrayTwo are all the same length.
 // will swap the elements from arrayOne to ArrayTwo.
  def swap[T](arrayOne:Array[T], arrayTwo:Array[T] , f:(T,T) =>(T,T)) {
    for(i <- 0 until (arrayOne.length min arrayTwo.length)){
      val (left, right) = f(arrayOne(i),arrayTwo(i))
      arrayOne(i) = left
      arrayTwo(i) = right
    }
  }
}

object Main extends Application {

   val arrayOne = Array("A","B","C")
   val arrayTwo = Array("D","E","F")

 //If not specified the type String,the compiler throws "Missing Parameter Type" error

Util swap(arrayOne, arrayTwo,(elem1:String,elem2:String)=>(elem2,elem1))

}
like image 949
CHAPa Avatar asked Mar 25 '10 15:03

CHAPa


1 Answers

It doesn't infer the type of T because the only thing it has to go by at this point would be arrayOne and arrayTwo. However, Scala does not use the type of one parameter to infer the type of another, probably because it would cause problems with method overloading. However, it works if you curry it:

Object Util {

 // Just for fun! Suppose that the arrayOne and arrayTwo are all the same length.
 // will swap the elements from arrayOne to ArrayTwo.
   def swap[T](arrayOne:Array[T], arrayTwo:Array[T])(f:(T,T) =>(T,T)) : Unit = {
     var i = 0   
        var tuple :Tuple2[T,T] = null
       while(i < arrayOne.length && i < arrayTwo.length){
         tuple =f(arrayOne(i),arrayTwo(i))
         arrayOne(i) = tuple._1
         arrayTwo(i) = tuple._2
         i+=1
        }
      }
}

object Main extends Application {

   // val works fine below -- the object is mutable
   val arrayOne = Array("A","B","C")
   val arrayTwo = Array("D","E","F")

   (Util swap(arrayOne, arrayTwo))((elem1,elem2)=>(elem2,elem1))
   // The weird parenthesis is caused by mixing operator notation and currying
   // One could also write it like this:
   // Util.swap(arrayOne, arrayTwo)((elem1,elem2)=>(elem2,elem1))
}

The reason why it works fine if you curry it is that a curried method is actually a method receiving the first parameter list and returning a function that requires the other (or others) parameter list. Because of that, overloading can be decided in the first parameter list, so the second parameter list can take advantage of inferred types.

like image 155
Daniel C. Sobral Avatar answered Oct 11 '22 22:10

Daniel C. Sobral