Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala: implement a generic recursive max function

I'm trying to port this haskell max function implementation to scala

maximum' :: (Ord a) => [a] -> a  
maximum' [] = error "maximum of empty list"  
maximum' [x] = x  
maximum' (x:xs) = max x (maximum' xs) 

This is my first attempt:

def max[T <: Ordered[T]](list: List[T]): T = list match {

  case Nil => throw new Error("maximum of empty list")
  case head :: Nil => head
  case list => {
    val maxTail = max(list.tail)
    if (list.head > maxTail) list.head else maxTail
  }
}


max(List[Int](3,4))

But I get the following error:

inferred type arguments [Int] do not conform to method max's type parameter bounds [T <: Ordered[T]]

I tried with ordering, comprable, etc with similar results...

Any idea about what's missing?

like image 467
opensas Avatar asked Sep 20 '12 05:09

opensas


2 Answers

Went through a similar exercise as the OP sans pattern matching and generic types, and came up with the following:

def max(xs: List[Int]): Int = {
    if (xs.isEmpty) throw new NoSuchElementException

    if (xs.length == 1) 
        return xs.head 
      else 
        return max(xs.head, max(xs.tail))
  }

  def max(x: Int, y: Int): Int = if (x > y) x else y
like image 157
dejon97 Avatar answered Sep 17 '22 14:09

dejon97


Maybe you want the Ordering type class?

def max[T: Ordering](list: List[T]): T = list match {
  case Nil => throw new RuntimeException("maximum of empty list")
  case head :: Nil => head
  case list =>
    val maxTail = max(list.tail)
    if (implicitly[Ordering[T]].gt(list.head, maxTail)) list.head else maxTail
}

This is, after all, how the built-in max method works:

// From GenTraversableOnce
def max[A1 >: A](implicit ord: Ordering[A1]): A

You can clean things up a lot if you do this:

def max[T](list: List[T])(implicit ord: Ordering[T]): T = list match {
  case Nil => throw new RuntimeException("maximum of empty list")
  case head :: Nil => head
  case head :: tail => ord.max(head, max(tail))
}

Or, you can make it tail-recursive for increased efficiency (because the compiler will optimize it):

def max[T](list: List[T])(implicit ord: Ordering[T]): T = {
  if (list.isEmpty)
    throw new RuntimeException("maximum of empty list")

  @tailrec
  def inner(list: List[T], currMax: T): T =
    list match {
      case Nil => currMax
      case head :: tail => inner(tail, ord.max(head, currMax))
    }
  inner(list.tail, list.head)
}

Also, you should throw RuntimeException or a subclass of it, not Error.

like image 43
dhg Avatar answered Sep 18 '22 14:09

dhg