Top Banner
Introducción a Scala Jose Emilio Labra Gayo Depto. Informática Universidad de Oviedo
57

4 Introducción al lenguaje Scala

Apr 15, 2017

Download

Engineering

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 4 Introducción al lenguaje Scala

Introducción a Scala

Jose Emilio Labra GayoDepto. Informática

Universidad de Oviedo

Page 2: 4 Introducción al lenguaje Scala

Scala

Creado en 2003 por Martin Odersky Lenguaje Funcional y Orientado a Objetos

Tipado estáticoInfluencias: Java, HaskellCompila a JVM

Martin Odersky, Fuente: http://lampwww.epfl.ch/~odersky/

Object Oriented meets Functional. Have the best of both worlds

Page 3: 4 Introducción al lenguaje Scala

Ecosistema

Página: https://www.scala-lang.orgImplementaciones:

Scala (compila a JVM), ScalaJS (compila a Javascript)Versiones en funcionamiento:

2.9 (2011), 2.10 (2013) , 2.11 (2014)Intérprete: scala Compilador: scalacConstrucción: sbt (http://www.scala-sbt.org)Búsqueda: http://scalex.org/Documentación: http://docs.scala-lang.org/

Page 4: 4 Introducción al lenguaje Scala

Hola Mundo en Scala

object Saluda { def main(args: Array[String]) = println("Hola desde Scala!")

}

Varias formas de ejecutarlo:Intérprete: scalaCompilador: scalac

> scala holaMundo.scalaHola desde Scala!

> scalac holaMundo.scala

> scala holaMundoHola desde Scala!

holaMundo.scala

Page 5: 4 Introducción al lenguaje Scala

Conceptos básicos

Lenguaje funcional y Orientado a ObjetosDiferencia entre valores y variables

val x = 5 //> x : Int = 5println(x) //> 5x = x + 1 //> error: reassignment to val

var x = 6 //> x : Int = 6x = x + 1println(x) //> 7

Page 6: 4 Introducción al lenguaje Scala

Chequeo e inferencia de Tipos

Chequeo estático de tiposTiempo de compilaciónObjetivo: Si compila, entonces no hay error de tipos

Sistema de inferencia de tiposMuchas declaraciones de tipos = opcionalesSi se declara, se comprueba que está bien

val x: Int = 2 + 3 //> x : Int = 5val y = 2 + 3 //> y : Int = 5val z: Boolean = 2 + 3 //> error: type mismatch; found : Int(5) required: Boolean

Page 7: 4 Introducción al lenguaje Scala

Sintaxis básica

Nombres de variabes similar a JavaBloque de sentencias entre { } y separados por ;Valor del bloque = valor de último elementoUn bloque es una expresión

Page 8: 4 Introducción al lenguaje Scala

Sintaxis básica

Las sentencias tienen un ; al finalPero en muchas ocasiones puede omitirseEl Sistema lo infiere

{ val x = 3 x + x}

{ val x = 3 ; x + x}

NOTA: A veces se producen mensajes de error extraños (unexpected ;) Cuidado con expresiones del tipo:

val prueba = uno + dos

val prueba = uno + dos ;

val prueba = uno + dos

val prueba = uno ;+ dos ;

Page 9: 4 Introducción al lenguaje Scala

Ámbito de variables

Variables localesDefiniciones en un bloque sólo visibles dentro de élDefiniciones en un bloque tapan definiciones externas

val x = 3def f(x: Int) = x + 1val resultado = { val x = f(3) x * x } + x

println(resultado) //> ??? ¿Qué imprime?

Page 10: 4 Introducción al lenguaje Scala

Sintaxis básica

Todo son expresiones

Numerosas simplificaciones( ) opcionales con métodos de 0 ó 1 argumento

. opcional (operador posfijo)

2 + 3 == 2.+(3)

juan.saluda()juan.saludajuan saluda

juan.saluda("Pepe")juan saluda("pepe")juan saluda "pepe"

val mensaje = if (edad > 18) "Puede votar" else "Es menor"

Page 11: 4 Introducción al lenguaje Scala

Sintaxis básica

Declaraciones de tipo después de variable

Integer suma(Integer a, Integer b) { return a + b;}

def suma(x:Int, y:Int) = x + y

Java Scala

val x: Int = 0Integer x = 0;Java Scala

No es necesario return

Page 12: 4 Introducción al lenguaje Scala

ScalaTest

Crear los siguientes métodospar(n) compruebe si un número es parfact(n) devuelve el factorial de un nº

https://gist.github.com/labra/2c16ad44ac484d0271d6ScalaTest de Factorial

Pasos a seguir:Descargar/clonar: https://github.com/cursosLabra/EjerciciosScala

Contiene una plantilla con la estructura de directoriesPruebas mediante ScalaTest

Utilizar SBT (Simple Build Tool)> sbt test

Page 13: 4 Introducción al lenguaje Scala

Objetos y clases

Herencia universal de ObjectNo hay tipos primitivosInt, Boolean, Float, Double, etc = clases

Object

AnyVal AnyRef

Int Long Double String... List ...

Nothing/Null

Page 14: 4 Introducción al lenguaje Scala

Declaración de Objetos

object permite definir objetos singletonobject juan { var edad = 34 val nombre = "Juan Manuel" def crece() { this.edad += 1 } def getEdad():Int = this.edad

def masViejo(otro: { def getEdad(): Int}) = this.edad > otro.getEdad}

NOTAScala es un lenguaje basado en clasesEn realidad, object crea un objeto singleton de una clase Juan

Page 15: 4 Introducción al lenguaje Scala

Clases: Estilo imperativo

Mediante classclass Persona(nombre: String, var edad: Int) { def crece(): Unit = { this.edad += 1 } def masViejo(otro: Persona): Boolean = { this.edad > otro.getEdad } def getEdad() = edad}

val juan = new Persona("Juan Manuel", 34)juan.creceprintln (juan.getEdad) //> 35

val pepe = new Persona("Jose Luis", 22)println(pepe.masViejo(juan)) //> false

edad es una variable que se actualiza

Objetos mutables

Este estilo no es recomendado

Page 16: 4 Introducción al lenguaje Scala

Constructores

Código dentro de la clase se ejecuta al crear nuevas instanciasthis permite definir otros constructoresclass Persona(nombre: String, edad: Int) { println("...inicializando") def this(nombre: String, recienNacido: Boolean) = { this(nombre, if (recienNacido) 0 else -1) } //... }

val luis = new Persona("Luis", 32) //> ...inicializando val kiko = new Persona("Kiko", true) //> ...inicializando

Page 17: 4 Introducción al lenguaje Scala

Clases: Estilo funcional

Objetos inmutablesOperaciones de escritura devuelven nuevos objetos

class Persona(nombre: String, edad: Int) { def crece(): Persona = { new Persona(nombre, this.edad + 1) } def masViejo(otro: Persona): Boolean = { this.edad > otro.getEdad } def getEdad() = edad}

val juan = new Persona("Juan Manuel", 34)println (juan.getEdad) //> 34val juan1 = juan.creceprintln (juan1.getEdad) //> 35println (juan.getEdad) //> 34

Page 18: 4 Introducción al lenguaje Scala

Herencia

Mediante extendsclass Usuario(nombre: String, edad:Int, email: String) extends Persona(nombre,edad) { def login(email: String): Boolean = { this.email == email } }def sumaEdades(personas:List[Persona]): Int = { personas.map(_.getEdad).sum}

val juan = new Persona("Juan", 34)val luis = new Usuario("Luis", 20, "[email protected]")println(sumaEdades(List(juan,luis))) //> 54

Page 19: 4 Introducción al lenguaje Scala

Ejercicio: Figuras

Crear una clase Figura con 2 atributos (x,y)Método que permita mover la figura

Crear una clase Rect para representar RectángulosAtributos a (ancho) y b (altura)

Crear una clase Circulo para representar CírculosAtributo r (radio)

Crear método area para calcular el areaCrear método areas que calcula el area de una lista de figuras

https://gist.github.com/labra/170a570f49922fd5281c

Page 20: 4 Introducción al lenguaje Scala

Estructuras de control

ifmatchwhilefor, foreachtry

Page 21: 4 Introducción al lenguaje Scala

Estructuras de control

if es similar a otros lenguajesDevuelve un valor

val mensaje = if (edad >= 18) "Puede votar" else "Es menor"

Page 22: 4 Introducción al lenguaje Scala

While, do...while

Similares a Java def mcd(x:Int,y:Int):Int = { var a = x var b = y while(a != 0) { val temp = a a = b % a b = temp } b}

NOTA: Los bucles While suelen ser imperativos. Pueden re-escribirse mediante recursividad

def mcd(x:Int,y:Int):Int = { if (x == 0) y else mcd(y % x,x)}

Page 23: 4 Introducción al lenguaje Scala

Bucles While e iteradores

def mediaEdad(personas: List[Persona]): Double = { var suma = 0 val it = personas.iterator while (it.hasNext) { val persona = it.next() suma += persona.edad } suma / personas.length}

Estilo imperativo

NOTA: Puede re-escribirse con estilo funcional:def mediaEdad(personas: List[Persona]): Double = { personas.map(_.edad).sum / personas.length}

Page 24: 4 Introducción al lenguaje Scala

Encaje de patrones

Expresión match dia match { case "Sabado" => println("Fiesta") case "Domingo" => println("Dormir") case _ => println("Programar en Scala") }

Expresión match devuelve un valor

val mensaje = dia match { case "Sabado" => "Fiesta" case "Domingo" => "Dormir" case _ => "Programar en Scala" }

Page 25: 4 Introducción al lenguaje Scala

Bucles for

for (i <- 1 to 4) print("x" + i) //> x1 x2 x3 x4

def pares(m:Int,n:Int): List[Int] = for (i <- List.range(m,n) if i % 2 == 0) yield i println(pares(0,10)) //> List(0,2,4,6,8,10)

Contienen: Generadores (suelen ser colecciones)Filtros (condiciones)yield: Valores que se devuelven

Si no hay yield se devuelve UnitSimilar a bucles convencionales de otros lenguajes

Page 26: 4 Introducción al lenguaje Scala

Excepciones

try...throw...catch...similar a Javadef divide(m:Int, n:Int) : Int = { if (n == 0) throw new RuntimeException("division por 0") else m / n }

try { println("5/4 = " + divide(5,4)) println("5/0 = " + divide(5,0)) } catch { case e: Exception => println("Error: " + e.getMessage) } finally { println("Fin") }

5/4 = 1Error: division por 0Fin

Page 27: 4 Introducción al lenguaje Scala

Clase Option

Option permite definir funciones parcialesPuede utilizarse para evitar uso de excepciones

def divide(m:Int, n:Int) : Option[Int] = { if (n == 0) None else Some(m / n)}

println("5/4 = " + divide(5,4)) //> Some(1)println("5/0 = " + divide(5,0)) //> None

NOTA: La clase Try puede también utilizarse.

Page 28: 4 Introducción al lenguaje Scala

Ejercicio

Calcular los factores primos de un númeroEjemplo:

factores 1 = [1]factores 2 = [1,2]factores 3 = [1,3]factores 4 = [1,2,2]factores 5 = [1,5]factores 6 = [1,2,3]...

https://gist.github.com/labra/270a37314524db303f7c

Page 29: 4 Introducción al lenguaje Scala

Funciones en Scala

Varias formas de declarar funciones

def suma(x:Int,y:Int): Int = x + y

def suma(x:Int,y:Int) = x + y

def suma(x:Int,y:Int): Int = { return x + y }

Procedimiento = función que devuelve valor de tipo Unit

def suma3(x:Int,y:Int) { println(x + y)}

def suma4(x:Int,y:Int):Unit = { println(x + y)}

Page 30: 4 Introducción al lenguaje Scala

Funciones en Scala

Simplificación

(x) => x + 3 _ + 3

val personas = List(Persona("Juan",34),Persona("Luis",23))

val edades = personas.map((x) => x.edad) //> List(34,23)

val edades = personas.map(_.edad) //> List(34,23)

Page 31: 4 Introducción al lenguaje Scala

Programación funcional

Funciones como valores

def suma3(x:Int) = x + 3def aplica2(f: Int => Int, x: Int) = f(f(x)) println(aplica2(suma3,2)) //> 8println(aplica2((x:Int) => x * x,2)) //> 16

val suma = (x:Int,y:Int) => x + y

Funciones de orden superior

Page 32: 4 Introducción al lenguaje Scala

Programación funcional

Currificación = funciones de un argumento que devuelven una función

def suma(x:Int)(y:Int):Int = x + y //> suma: Int => (Int => Int)

def suma = (x:Int) => ((y:Int) => x + y) //> suma: Int => (Int => Int)

suma(3) //> res: Int => Int = <function>suma(3)(2) //> 5: Int

println(List(1,2,3).map(suma(3))) //> List(4,5,6)

Page 33: 4 Introducción al lenguaje Scala

Tipos predefinidos

Numéricos: Int, BigInt, Float, DoubleBooleanStringRangosTuplasRegexNullAny, AnyVal, AnyRef

Page 34: 4 Introducción al lenguaje Scala

Números, booleanos y caracteres

Similares a Java pero sin tipos primitivosByte, Short, Int, Long, Float, DoubleRango disponible mediante MinValue, MaxValue

Ej. Int.MinValueTambién disponibles: BigInt, BigDecimalConversión mediante toX

Ej. "234".toInt

Boolean: valores true, falseChar: representa caracteres

Page 35: 4 Introducción al lenguaje Scala

Strings

Similares a JavaComparación mediante == (equals en Java)

Sintaxis """ para cadenas multílíneaNumerosas utilidades en StringOps

Page 36: 4 Introducción al lenguaje Scala

Rangos

Range(min,max) crea rango entre min y max

val ceroDiez = Range(1,10)

println (ceroDiez.contains(5)) //> true

for (i <- ceroDiez if i % 3 == 0) print(s"$i ") //> 3 6 9

Page 37: 4 Introducción al lenguaje Scala

Colecciones

Traversable

Iterable

Seq Set Map

IndexedSeq LinearSeq

ListVector StreamArray

Jerarquía de coleccionesSolo se muestran algunas

HashMap SortedMap

Page 38: 4 Introducción al lenguaje Scala

Listas

Construcción básica mediante :: y Nil

val x = 1 :: 2 :: 3 :: Nilval y = List(1,2,3)

println(x == y) //> true

Page 39: 4 Introducción al lenguaje Scala

Programación funcional

Map def map(ls: List[Int], f: Int => Int): List[Int] = ls match { case Nil => Nil case x :: xs => f(x) :: map(xs,f) }

println(map(List(1,2,3),_ + 3)) //> List(4,5,6)

Ejercicio:def fold(ls:List[Int], e: Int, op:(Int,Int)=>Int):Int = { ...}

Page 40: 4 Introducción al lenguaje Scala

Programación funcional

Combinadores = funciones que toman otras funciones como argumentosEjemplos en colecciones:

List[a].map: (f: (a) => b) => List[b]List[a].reduce: (op:(a,a) => a) => aList[a].foldLeft: (z:b)(op:(b,a) => b) => aList[a].foldRight: (z:b)(op:(a,b) => b) => a

...

NOTA: Los tipos se han simplificado por claridad

Page 41: 4 Introducción al lenguaje Scala

Vectores

Operación de indexación muy rápida

val frutas = Vector("Peras", "Limones", "Naranjas")println(frutas(1)) //> Limonesprintln((frutas :+ "Kiwis").length) //> 4

Page 42: 4 Introducción al lenguaje Scala

Maps

val notas = Map("Jose" -> 5.7, "Luis" -> 7.8)

for ((n,v) <- notas) println (s"${n} tiene un ${v}") Jose tiene un 5.7

Luis tiene un 7.8

Arrays asociativos (Tablas Hash)

Page 43: 4 Introducción al lenguaje Scala

Ejercicio con agregación

Modelar cursos con alumnosUna clase curso compuesta por:

Nombre del cursoLista de alumnos

Una clase alumno compuesta porid del alumnonota del alumno

Definir métodos de curso: getNota(id)ponNota(id,nota)media

Curso Alumno1..n1

https://gist.github.com/labra/79e6d273986487bc68d0

Page 44: 4 Introducción al lenguaje Scala

Objeto acompañante

objecto con mismo nombre que una clase ó traitEs un objeto singleton (una única instancia)Tiene acceso a campos/métodos privadosUso habitual: métodos/atributos estáticos

En Scala no hay staticMétodo apply() puede usarse como factoríaMétodo unapply() permite extraer elementos

Page 45: 4 Introducción al lenguaje Scala

Objeto acompañanteclass Persona(nombre:String, edad:Int) { def getEdad = edad def masViejo(otro:Persona) = this.edad > otro.getEdad}

object Persona { def apply(nombre:String): Persona = new Persona(nombre,15) def apply(edad:Int): Persona = new Persona("Sin nombre",edad) }

val juan = Persona("Juan")val x = Persona(10)

println(juan.masViejo(x)) //> true

Page 46: 4 Introducción al lenguaje Scala

case ClassesPermite simplificar declaraciones

case class Persona(nombre:String, edad:Int)

val juan = Persona("Juan", 34) //> Persona(Juan,34)val luis = Persona("Luis", 23) //> Persona(Luis,23) println(juan.nombre) //> "Juan"println(juan == luis) //> false

Notacase Classes permiten crear patrón ValueObject: http://en.wikipedia.org/wiki/Value_object

Objetos funcionales (inmutables)Genera getters de los camposCrea objeto acompañante (fabricar instancias sin new)Genera equals,hashCode,toString

Page 47: 4 Introducción al lenguaje Scala

public class Persona { private String nombre; private Integer edad; public String getNombre() { return nombre; } public Integer getEdad() { return edad; } @Override public boolean equals(Object otro) { if (otro == this) return true; if (!(otro instanceof Persona)) return false; Persona p = (Persona) otro; return p.nombre == nombre && p.edad == edad; }

@Override public int hashCode(){ int result = 17; result = 31* result + (nombre !=null ? nombre.hashCode() : 0); result = 31* result + (edad !=null ? edad.hashCode() : 0); return result; }

@Override public String toString() { return String.format("Persona[name=%s,birthdate=%d]", nombre, edad); }}

Javacase class Persona(nombre:String, edad:Int)

En Java, puede usarse el proyecto Lombok: http://projectlombok.org/

Comparación con JavaScala

Page 48: 4 Introducción al lenguaje Scala

traits

Reutilización de comportamientotrait Saludador { def saluda(nombre: String) { println("Hola " + nombre + ", soy " + this.toString) }} case class Persona(nombre:String, edad:Int) extends Saludadorcase class Coche(marca:String) extends Saludador val r21 = Coche("Renault XXI")val juan = Persona("Juan Manuel",34) r21.saluda("Pepe") //> Hola Pepe, soy Coche(Renault XXI) juan.saluda("Pepe") //> Hola Pepe, soy Persona(Juan Manuel,34)

Page 49: 4 Introducción al lenguaje Scala

Ejercicio Hashes y Arrays

Corregir exámenes. Aciertos: +1, fallos: -0.25

[ {"pregunta" => 1, "correcta" => "a"}, {"pregunta" => 2, "correcta" => "b"}]

[ {"alumno" => 2456, "respuestas" => [{ "pregunta" => 1, "respuesta" => "a"}, { "pregunta" => 2, "respuesta" => "b"}]}, {"alumno" => 4321, "respuestas" => [{ "pregunta" => 1, "respuesta" => "b"}, { "pregunta" => 2, "respuesta" => "b"}]}]

[ {"alumno" => 2456, "nota" => 2}, {"alumno" => 4321, "nota" => 0.75}]

https://gist.github.com/labra/1c2bdf6ec9201ba14d73

Page 50: 4 Introducción al lenguaje Scala

Variables estáticas mediante object

object puede usarse para recoger métodos y variables estáticasclass Persona(nombre:String, edad:Int) object Persona { private var cuentaPersonas = 0 def apply(nombre:String, edad:Int): Persona = { cuentaPersonas += 1 new Persona(nombre,edad) } def totalPersonas(): Int = { cuentaPersonas }}

val juan = Persona("Juan",23)val luis = Persona("Luis",31)println(Persona.totalPersonas) //> 2

Page 51: 4 Introducción al lenguaje Scala

Modularización

package = objeto especial para agrupar códigoimport: permite importar código

Similar a Java, pero utiliza _ en lugar de *Permite declarer qué elementos se importan

Incluso renombrar elementos al importarlos

import io.AnsiColor._import math.{log => logaritmo,_}

object Modularidad { println(MAGENTA + "Hola" + RESET) println(logaritmo(E)) }

Page 52: 4 Introducción al lenguaje Scala

Genericidad

Valores con un tipo genérico

def map[A](ls: List[A], f: A => A): List[A] = ls match { case Nil => Nil case x :: xs => f (x) :: map(xs,f)}

Ejercicio: Definir una función fold genérica

def fold[A,B](ls: List[A], e: B, op: (A,B) => B): B = { ...}

Page 53: 4 Introducción al lenguaje Scala

Tipos abstractos de datossealed trait Arbol[A]case class Hoja[A](info:A) extends Arbol[A]case class Rama[A](izq:Arbol[A],der:Arbol[A]) extends Arbol[A] def nodos[A](a: Arbol[A]): Int = a match { case Hoja(_) => 1 case Rama(izq,der) => nodos(izq) + nodos(der)}

def sumaNodos(a: Arbol[Double]): Double = a match { case Hoja(n) => n case Rama(izq,der) => sumaNodos(izq) + sumaNodos(der)}

val a = Rama(Hoja(5.0),Rama(Hoja(5.5),Hoja(9.5)))println(nodos(a)) //> 3println(sumaNodos(a)) //> 20.0

Page 54: 4 Introducción al lenguaje Scala

Parámetros implícitos

implicit declara parámetros que toman un valor implícito en un contexto

def saluda(nombre:String)(implicit fin: String): Unit = { println("Hola " + nombre + fin)}

implicit val exc: String = "!" saluda("Pepe") //> Hola Pepe!saluda("Luis")("!!!") //> Hola Pepe!!!

Page 55: 4 Introducción al lenguaje Scala

Otras características

lazy vals y paso por nombreStreamspackage objectsvalue objectsvarianza/covarianza de tipostipos de rango superiorclases implícitas...

Page 56: 4 Introducción al lenguaje Scala

Referencias

Tutoriales:http://docs.scala-lang.org/http://twitter.github.io/scala_school/

Guía de estilo: http://twitter.github.io/effectivescala/

Artículo acerca del lenguajeUnifying Functional and Object Oriented Programming, Martin OderskyCommunications of the ACMhttp://cacm.acm.org/magazines/2014/4/173220-unifying-functional-and-object-oriented-programming-with-scala/fulltext

Page 57: 4 Introducción al lenguaje Scala

Libros