Introduccion a Scala
Scala es un lenguaje de programación multiparadigma: imperativo, orientado a objetos, basado en eventos, funcional, concurrente, etc.
Nos vamos a enfocar en el paradigma funcional, por lo tanto debemos usar elementos como:
defovalpara declarar funciones o valores inmutables; no podemos usarvar.- Todo lo que se hace va a terminar en un valor.
- Accedemos a las estructuras usando recursión.
Anotaciones¶
- Object es una clase estática, porque hay una sola instancia de esa clase en todo el programa; no se permite tener más instancias. Por esta razón, la clase que contiene el método
maindebe ser estática. - Declaraciones:
// Declaración de una función que recibe dos enteros y retorna un entero
def funcion(a: Int, b: Int): Int = {
// muchas instrucciones
// Va a retornar la última expresión evaluada
a + b // Esta sería la expresión retornada
}
// Declaración de un valor inmutable (equivalente a 'final' en Java)
def variableA = 5 // Esto es una función sin parámetros que siempre retorna 5
val variableB = 8 // Esto es un valor inmutable
Conceptos teóricos adicionales¶
Características principales de Scala¶
- Interoperabilidad con Java: Scala corre en la JVM y puede usar bibliotecas Java directamente.
- Inferencia de tipos: El compilador puede deducir tipos en muchas situaciones, reduciendo código boilerplate.
- Pattern matching: Mecanismo poderoso para descomponer datos, similar a
switchen otros lenguajes pero más expresivo. - Case classes: Clases especiales optimizadas para pattern matching y inmutabilidad.
- Traits: Similar a interfaces en Java pero pueden contener implementación de métodos (mixin composition).
- For-comprehensions: Sintaxis para trabajar con colecciones de manera declarativa.
Programación funcional en Scala¶
- Funciones como ciudadanos de primera clase: Las funciones pueden ser asignadas a variables, pasadas como argumentos y retornadas como resultados.
- Inmutabilidad por defecto: Se favorece el uso de
valsobrevarpara evitar efectos secundarios. - Funciones puras: Funciones que no tienen efectos secundarios y siempre retornan el mismo resultado para los mismos argumentos.
- Recursión: En lugar de bucles, se usa recursión. Scala optimiza la recursión de cola con
@tailrec. - Colecciones inmutables: Scala proporciona colecciones inmutables como
List,Set,Mapen el paquetescala.collection.immutable.
Ejemplo de código Scala funcional¶
// Ejemplo de función recursiva para calcular factorial
def factorial(n: Int): Int = {
if (n <= 1) 1
else n * factorial(n - 1)
}
// Versión con recursión de cola (optimizada)
import scala.annotation.tailrec
def factorialTailRec(n: Int): Int = {
@tailrec
def loop(acc: Int, n: Int): Int = {
if (n <= 1) acc
else loop(acc * n, n - 1)
}
loop(1, n)
}
// Uso de funciones de orden superior
val numbers = List(1, 2, 3, 4, 5)
val doubled = numbers.map(x => x * 2) // List(2, 4, 6, 8, 10)
val sum = numbers.foldLeft(0)(_ + _) // 15
Tabla de resumen de conceptos¶
| Concepto | Descripción | Ejemplo en Scala |
|---|---|---|
val |
Declara un valor inmutable (no puede reasignarse) | val x = 10 |
var |
Declara una variable mutable (puede reasignarse) | var y = 20 (evitar en programación funcional) |
def |
Declara un método o función | def suma(a: Int, b: Int): Int = a + b |
object |
Define una clase singleton (una sola instancia) | object MiApp { def main(args: Array[String]): Unit = ... } |
| Inferencia de tipos | El compilador deduce el tipo automáticamente | val lista = List(1, 2, 3) // List[Int] |
| Funciones de orden superior | Funciones que reciben o retornan otras funciones | lista.map(x => x * 2) |
| Pattern matching | Descomposición de datos basada en patrones | x match { case 1 => "uno"; case _ => "otro" } |
| Case class | Clase optimizada para pattern matching e inmutabilidad | case class Persona(nombre: String, edad: Int) |
| Trait | Similar a interfaz con implementación parcial | trait Animal { def sonido: String } |
| Recursión de cola | Recursión donde la llamada recursiva es la última operación | @tailrec def loop(...): ... |
| Colecciones inmutables | Estructuras de datos que no pueden modificarse después de creadas | List(1, 2, 3), Set(1, 2, 3), Map("a" -> 1) |
| For-comprehension | Sintaxis para trabajar con colecciones de manera declarativa | for (x <- lista if x > 0) yield x * 2 |
Comentarios adicionales¶
-
Transición de Java a Scala: Para programadores Java, Scala puede parecer complejo inicialmente debido a su sintaxis concisa y capacidades funcionales. Sin embargo, Scala permite escribir código más expresivo y seguro, especialmente para procesamiento de datos y programación concurrente.
-
Aplicaciones típicas de Scala:
- Procesamiento de datos a gran escala (Apache Spark está escrito en Scala)
- Sistemas distribuidos y concurrentes
- APIs web (usando frameworks como Akka HTTP, Play Framework)
-
Scripting y herramientas de línea de comandos
-
Herramientas del ecosistema Scala:
- sbt: Herramienta de construcción principal
- ScalaTest, Specs2: Frameworks de testing
- Cats, ZIO: Bibliotecas para programación funcional pura
-
Akka: Toolkit para sistemas concurrentes y distribuidos
-
Mejores prácticas en Scala funcional:
- Preferir
valsobrevarsiempre que sea posible - Usar
Option,Either,Tryen lugar denullo excepciones para manejo de errores - Aprovechar la inferencia de tipos pero ser explícito en APIs públicas
- Usar recursión de cola con
@tailrecpara evitar desbordamiento de pila -
Aplicar principios de inmutabilidad y transparencia referencial
-
Relación con los ejercicios en Java: Los ejercicios vistos en Repaso conceptos pueden reescribirse en Scala de manera más concisa y funcional. Por ejemplo, la búsqueda de tripletas podría implementarse usando for-comprehensions y la serie de Fibonacci podría implementarse con streams/lazy evaluation para mayor eficiencia.
-
Desafíos comunes:
- Curva de aprendizaje pronunciada para programadores imperativos
- Compilación más lenta que Java en proyectos grandes
-
Necesidad de entender tanto programación funcional como orientada a objetos
-
Recursos recomendados:
- "Programming in Scala" de Martin Odersky (creador de Scala)
- "Functional Programming in Scala" (libro rojo)
- Documentación oficial en scala-lang.org
-
Coursera: "Functional Programming Principles in Scala"# Solución del problema
-
Programe una función que genere todos los números entre n y m, n <= m, que cumplan a³ + b³ = c³ y debe retornar una estructura que tenga todas las tuplas (a,b,c) que cumplen esto.
- Genere un programa que me de la lista de la serie de fibunnaci desde 0 hasta n. Recursivo
/*
* This Scala source file was generated by the Gradle 'init' task.
*/
package taller
object App {
def punto1(n:Int, m:Int):List[List[Int]] = {
(for {
a <- (n to m).toList
b <- (n to m).toList
c <- (n to m).toList
if (a*a*a+b*b*b == c*c*c)
} yield List(a,b,c)).toList
}
def fibunnacci(n:Int):Int = {
if (n<=1) n
else fibunnacci(n-1)+fibunnacci(n-2)
}
def listaFibunnacci(n:Int):List[Int] = {
(0 to n).map(x => fibunnacci(x)).toList
}
def main(args: Array[String]): Unit = {
println(punto1(1,100))
println(listaFibunnacci(10))
}
}