Operators on Parameterized Type in Scala

For a higher order function that takes a function of type (A, A) => Boolean as a parameter:

 def isSorted[A](as: Array[A], ordered :  (A,A) => Boolean) : Boolean =
 {
   def doSorted(i: Int) : Boolean = 
     if (i >= as.length-1) true
     else if (ordered(as(i), as(i+1))) false
     else doSorted(i+1)

  doSorted(0)
 }
 val lst1 = Array(1,2,3,4,5,6)

      

I can declare a function with known parameter types and pass it to:

 def gtr(a : Int, b : Int) : Boolean = {
   a > b
 }

isSorted(lst1,gtr) /* works :-) */

      

I would like to do one of the following. None of these seem to work for me:

  • Use a function with parameterized types:

     def gtr[T](a : T, b : T) : Boolean = {
          a > b    /* gives value > is not a member of type parameter T */
     }
    
          

    Is this possible in Scala. Should I tell the compiler that T is inherited from an object that has a p> operator

  • Use an anonymous function:

    isSorted(lst1, ((x,y) => x > y)) /* gives missing parameter type */
    
          

  • Use Scala underscore mask to pass operator>

    isSorted(lst1, _>_) /* gives missing parameter type */
    
          

None of these three options work for me and I am struggling to figure out why. Can anyone tell me which of the above approaches are valid in Scala and what I am doing wrong.

+3


source to share


2 answers


The problem is that your type parameter A

has no restrictions, which means you can pass any type. But this cannot be, because not every type has a method >

, as you say. There is also no generic type that other types inherit from >

. The only option is class classes for which we have an Ordering class . You will need to require to Ordering[A]

exist (implicitly) in your method signature.

I'll do this for a method greater

with one caveat. We will need to curry the parameters isSorted

.

def isSorted[A](as: Array[A])(ordered: (A, A) => Boolean): Boolean = {
    def doSorted(i: Int) : Boolean = 
        if (i >= as.length - 1) true
        else if (ordered(as(i), as(i + 1))) false
        else doSorted(i + 1)

    doSorted(0)
}

      

We now define greater

to implicitly find Ordering[A]

. Once we get one, we can use its method gt

for the actual comparison.

def greater[A: Ordering](a: A, b: A): Boolean = implicitly[Ordering[A]].gt(a, b)

      



This is the same as:

def greater[A](a: A, b: A)(implicit ord: Ordering[A]): Boolean = ord.gt(a, b)

      

Using:

scala> isSorted(Array(1, 2, 3, 4))(greater _)
res88: Boolean = true

scala> isSorted(Array(1, 4, 3, 4))(greater _)
res89: Boolean = false

      

+3


source


You're right. You need to indicate that T can be compared. One approach is to use view boundaries:

    def gtr[T <% Ordered[T]](a : T, b : T) : Boolean = {
      a > b  
 }

      

[T <% Ordered[T]]

can be read as " can be seen as " (extended or implicitly converted). This approach is now deprecated https://issues.scala-lang.org/browse/SI-7629 ), so you can use implicit proofs to convert to T

Ordered[T]

T

Ordered[T]

def gtr[T](a : T, b : T)(implicit toOrdered: T => Ordered[T]) : Boolean

      



A very nice post that explains the scope of the overview in more detail: What are the scope and scope of Scala?

Regarding your 2nd and 3rd questions: in the second example, you need to infer the types for x and y in order to compile the code. 3rd is just syntactic sugar for 2nd. Both of them will compile.

isSorted(Array(1,2,3,4,5,6), ((x : Int,y: Int) => x > y))
isSorted(Array(1,2,3,4,5,6), ((_: Int) > (_: Int)))

      

+3


source







All Articles