scala: implementar una función máxima recursiva genérica
generics recursion (5)
¿Tal vez quieres la clase de tipo de orden?
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
}
Esto es, después de todo, cómo funciona el método de max
integrado:
// From GenTraversableOnce
def max[A1 >: A](implicit ord: Ordering[A1]): A
Puedes limpiar mucho si haces esto:
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))
}
O bien, puede hacer que sea recursivo para una mayor eficacia (porque el compilador lo optimizará):
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)
}
Además, debe lanzar RuntimeException
o una subclase de ella, no Error
.
Estoy tratando de portar esta implementación de la función haskell max a scala
maximum'' :: (Ord a) => [a] -> a
maximum'' [] = error "maximum of empty list"
maximum'' [x] = x
maximum'' (x:xs) = max x (maximum'' xs)
Este es mi primer intento:
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))
Pero me sale el siguiente error:
inferred type arguments [Int] do not conform to method max''s type parameter bounds [T <: Ordered[T]]
Intenté con ordenar, comprable, etc. con resultados similares ...
¿Alguna idea sobre lo que falta?
Acabo de presentar esta solución.
def max(xs: List[Int]): Int = {
if (xs.isEmpty) 0
else {
if( xs.head >= max(xs.tail) ) xs.head
else max(xs.tail)
}
}
Se me ocurrió una solución bastante simple que es fácil de entender. Ofrece una lista vacía, una lista con un solo elemento y números negativos.
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new NoSuchElementException
else {
def inner(max: Int, list: List[Int]): Int = {
def compare(x: Int, y: Int): Int =
if (x > y) x
else y
if (list.isEmpty) max
else inner(compare(max, list.head), list.tail)
}
inner(xs.head, xs.tail)
}
}
Realicé un ejercicio similar al OP sin emparejar patrones y tipos genéricos, y obtuve lo siguiente:
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
Uy, debería verse mejor antes de preguntar
Encontré la respuesta en este hilo: https://.com/a/691674/47633
Parece que las clases de tipos de Haskell se implementan usando implícitos en scala (como en el ejemplo de dhg)
por lo que termina así:
def max[T](list: List[T])(implicit f: T => Ordered[T]): T = {
def maxElement(value1: T, value2: T): T = if (value1 > value2) value1 else value2
list match {
case Nil => throw new Error("empty list found")
case head :: Nil => head
case list => maxElement(list.head, max(list.tail))
}
}
o con un poco de azúcar sintáctico, solo
def max[T <% Ordered[T]](list: List[T]): T = list match {
Aún así, creo que el compilador tiene suficiente información para hacerlo solo ...
pd: preparé un poco la función ...