Catecbol www.catecbol.com
Capacitación Tecnológica Científica para Bolivia facebook.com/catecbol
@catecbol
Fundamentos de Scala Jean-Paul Calbimonte University of Applied Sciences and Arts Western Switzerland, HES-SO
La unión es la fuerza
[email protected]
Jean-Paul Calbimonte Formación académica: • Ingeniería de Sistemas: Universidad Católica Boliviana, Bolivia • Master en Informática: École Polytechnique Fédérale de Lausanne EPFL, Suiza
• Doctorado en Inteligencia Artificial: Universidad Politécnica de Madrid, España Experiencia:
• Investigador adjunto, University of Applied Sciences and Arts Western Switzerland • Postdoctorado, École Polytechnique Fédérale de Lausanne EPFL, Suiza • Software dev: pirAMide informatik, medspazio, Cochabamba Área de Investigación: • Procesamiento de streams, RDF streams, ingeniería ontológica, e-Health
http://jeanpi.org
Fundamentos de Scala
¿Qué es Scala? sintaxis concisa
lenguaje escalable
corre en JVM
tipos estáticos
compatible con Java abstracción concurrencia, multi-hilos
orientado objetos + funcional
ecosistema Scala
Scala: ideas básicas 1. todo valor es un objeto
2. toda funcion es un valor
Scala combina ambos paradigmas
Scala: un vistazo
Prueba Scala en línea ahora mismo!
http://tinsmith.herokuapp.com/
Scala: expresiones y tipos cada expresión es una función que resulta en un valor 1 //> res0: Int(1) = 1 true //> res1: Boolean(true) = true 2+3 //> res2: Int(5) = 5 2.4+3 //> res3: Double(5.4) = 5.4 math.Pi //> res4: Double(3.141592653589793) = 3.141592653589793 math.log(1) //> res5: Double = 0.0 "cadena" //> res6: String("cadena") = cadena "cadena" + 4 //> res7: String = cadena4 3/0 //> java.lang.ArithmeticException: / by zero
cada valor tiene un tipo de dato, e.g. Int, String
2+3
//> res2: Int(5) = 5
Scala: diseccionando una expresión 2+3
//> res2: Int(5) = 5 se puede escribir como:
2.+(3) objeto
//> res8: Int(5) = 5 argumento
método
"34".toInt < 20 //> res9: Boolean = false
Scala: valores y variables se infiere
val num=3 //> num : Int = 3 el tipo println(num) //> 3 val texto="catecbol" //> texto : String = catecbol val num2:Int=3 //> num2 : Int = 3 val mix="texto"+34+true //> mix : String = texto34true declaración explícita
var num3=3 num3 = 5 // no se puede reasignar un val ❌num2 = 5 // no se puede reasignar con otro tipo ❌num3 = "texto"
Scala: funciones (s:String) => "cadena" + s
//> res0: String => String =
función anónima
cuerpo de la parámetro función val sumarPi = (num:Int) => Pi+num //> sumarPi : Int => Double = sumarPi(23) //> res1: Double = 26.141592653589793 val puede ser una función
val calcular=(n1:Int,n2:Double) => { val n3=n1*n2 n3*5 } //> calcular : (Int,Double) => Double = calcular(3,4.5) //> res2: Double = 67.5
Scala: colecciones val arr1=Array(3,5,6,4) //> arr1 : Array[Int] = Array(3, 5, 6, 4) val arr2=Array(Array(5,4,2) Array(3,2,4), Array(1,5,4)) arr1(2) arr2.flatten
//> res0: Int = 6 //> res1: Array[Int] = Array(5,4,2,3,2,4,1,5,4)
val arr3=ArrayBuffer(3,2,4) //> scala.collection.mutable.ArrayBuffer[Int] arr3+=4 //> res2: ArrayBuffer(3, 2, 4, 4)
Scala: colecciones val map1=Map("cbba"->"Cochabamba", "lp" ->"La Paz", "tri" ->"Trinidad")
map1("cbba") //> res3: String = Cochabamba map1.getOrElse("abc", "ninguno") //> res4: String = ninguno
val bol=("bol","Bolivia") val chi=("chi","Chile") val arg=("arg","Argentina")
Seq(bol,chi,arg).toMap map1.asJava
//> res5: scala.collection.immutable .Map[String,String] //> res6: java.util.Map[String,String]
Scala: listas List(1,3,5,6,9) Seq(3,6,8,9) (1 to 6) (0 until 10)
//> res0: List[Int] = List(1, 3, 5, 6, 9) //> res1: Seq[Int] = List(3, 6, 8, 9) //> res2: Range(1, 2, 3, 4, 5, 6) //> res3: Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
val lista=(1 to 5) //> lista: Range(1, 2, 3, 4, 5) lista.filter(i => i res4: Vector(1, 2, 3) lista.filter(i=>i%2==0) //> res5: Vector(2, 4) lista.map(i=>i*2) //> res6: Vector(2, 4, 6, 8, 10) lista.sum //> res7: Int = 15 lista.foreach(i => println(s"*$i*")) //| *2* //| *3* //| *4* //| *5*
//> *1*
Scala: listas
val lista2=List(3,5.6,45,"hola",34.5,"chau")
lista2.head //> res8: Any = 3 lista2.take(3) //> res9: List[Any]=List(3, 5.6, 45) "adios" :: lista2 //> res10: List(adios, 3, 5.6, 45, hola, 34.5, chau)
List(20,30) ::: List(40,50) //> res11: List(20, 30, 40, 50) lista2.map { case s:String=>"*" case _ => "+" } //> res12: = List(+, +, +, *, +, *)
Scala: cadenas val s1="cadena" s1.split('a')
//> s1 : String = cadena //> res0: Array[String] = Array(c, den)
val s2=s"$s1 es un string"
//> s2 : String = cadena es un string
val num=34.56 //> num : Double = 34.56 val s3=f"$s1 y un valor de $num%2.1f" //> s3 : String = cadena y un valor de 34.6 val s4="""cadena de varias líneas"""
//> s4 : String = cadena de //| varias //| líneas
Scala: cadenas "ab,cd,ef;gh;ij".split(",|;") //> res1: Array[String] = Array(ab, cd, ef, gh, ij)
val r="[a-z]+".r //> r : scala.util.matching.Regex = [a-z]+
r.findFirstIn("2653abc7878") match { case Some(patron)=>patron } abc
//> res2: String =
Scala: clases class Banda(nombre:String,genero:String) val kjarkas=new Banda("Kjarkas","folclore") class Musico(val nombre:String,banda:Banda) { def cantar(cancion:String)={ println(s"♫♫ $cancion ♫♫") } } val elmer=new Musico("Elmer Hermosa",kjarkas) elmer.cantar("bolivia") println(elmer.nombre) println(elmer.banda)
//> ♫♫ bolivia ♫♫ //> Elmer Hermosa
Scala: clases class Instrumento(nombre:String,esAutoctono:Boolean=false){ override def toString= s"El instrumento: $nombre" }
val charango=new Instrumento("charango",true) val bajo=new Instrumento("bajo") println(bajo)
//> El instrumento: bajo
Scala: traits trait Artista{ val nombre:String val edad:Int } class Cantante(val nombre:String, val edad:Int, val discos:Int) extends Artista class Actor(val nombre:String,val edad:Int,val peilculas:Int) extends Artista val luzmila=new Cantante("Luzmila Carpio",50,30 val jenny=new Actor("Jenny Serrano",40,2)
val artistas=Seq(luzmila,jenny) artistas.foreach(artista=>println(artista.nombre)) //> Luzmila Carpio //| Jenny Serrano
Scala: clases class Cancion(val titulo:String) trait Cantante{ def cantar(cancion:Cancion) } trait Compositor{ def componer(titulo:String):Cancion } class Cantautor extends Cantante with Compositor{ def componer(titulo:String)={ new Cancion(titulo) } def cantar(cancion:Cancion)= println(s"♫♫ ${cancion.titulo} ♫♫") }
val matilde=new Cantautor val regreso=matilde.componer("Regreso") matilde.cantar(regreso) //> ♫♫ Regreso ♫♫
Scala: objetos singleton class Departamento(val nombre:String) object Cochabamba extends Departamento("Cochabamba") object Beni extends Departamento("Beni") def iniciales(dpto:Departamento)= dpto.nombre.take(3) iniciales(Beni)
//> res0: String = Ben
object Departamento{ def apply(s:String)=new Departamento(s) } Departamento("Tarija") object Geometria { def area(radio:Int)=math.Pi*radio*radio } Geometria.area(4) //> res2: Double = 50.26548245743669
Scala: clases case case class PlatoTipico(nombre:String,departamento:String) val majao=PlatoTipico("majadito","Santa Cruz") val fricase=PlatoTipico("fricase","La Paz")
println(majao.departamento) //> Santa Cruz val majadito=PlatoTipico("majadito","Santa Cruz") majao == majadito //> res0: Boolean = true
val sonso=majao.copy(nombre="sonso") println(sonso) //> PlatoTipico(sonso,Santa Cruz)
Scala: match case def evaluar(nota:String)={ nota match { case "A" => 70 case "B" => 50 case "F" => 30 case _ => 0 } } //> evaluar: (nota: String)Int evaluar("B") evaluar("h")
//> res0: Int = 50 //> res1: Int = 0
def verificar(a:Any)=a match{ case "A" => "una letra A" case 4 => "un int 45" case 4.5 => "un double 4.5" } //> verificar: (a: Any)String verificar("A") //> res2: String = una letra A // match error verificar("a")
Scala: match case def verificar2(a:Any)=a match { case s:String => "string" case d:Double => "double" case i:Int => "int" case _ => "otro" } //> verificar2: (a: Any)String
Seq("ab",5,3.4,"2",List).map(verificar2) //> res3: Seq[String] = List(string, int, double, string, otro)
Scala: match case trait Region{ val nombre:String } case class Departamento(nombre:String) extends Region case class Provincia(nombre:String,dpto:Departamento) extends Region case class Municipio(nombre:String,prov:Provincia) extends Region val cocha=Departamento("Cochabamba") val cercado=Provincia("Cercado",cocha) val chuqui=Departamento("Chuquisaca") val oropeza=Provincia("Oropeza",chuqui) val sucre=Municipio("Sucre",oropeza) val list:Seq[Region]=Seq(cocha,cercado,oropeza,sucre)
Scala: match case val list:Seq[Region]=Seq(cocha,cercado,oropeza,sucre) list map { case Departamento(nom) => s"Depto $nom" case Provincia(nom,dpto) => s"prov $nom en ${dpto.nombre}" case Municipio(nom,prov) => s"muni $nom en ${prov.nombre}, dpto ${prov.dpto.nombre}" } //> res4: Seq[String] = List(Depto Cochabamba, prov Cercado en Cochabamba, prov //| Oropeza en Chuquisaca, muni Sucre en Oropeza, dpto Chuquisaca)
list map { case d:Departamento => s"Depto ${d.nombre}" case p:Provincia => s"prov ${p.nombre} en ${p.dpto.nombre}" case m:Municipio => s"muni ${m.nombre} en ${m.prov.nombre}, dpto ${m.prov.dpto.nombre}" } //> res5: Seq[String] = List(Depto Cochabamba, prov Cercado en Cochabamba, prov //| Oropeza en Chuquisaca, muni Sucre en Oropeza, dpto Chuquisaca)
Scala: opciones val equipos=Map("lp"->"The Strongest", "scz"->"Oriente", "cocha"->"Wilster", "oru"->"San Jose")
def obtenerEquipo(dpto:String):Option[String]={ equipos.get(dpto) } def hayEquipo(dpto:String)=equipos.get(dpto) match { case Some(eq) => println(s"el equipo es $eq") case None => println("no hay equipo") } hayEquipo("scz") hayEquipo("abc")
//> el equipo es Oriente //> no hay equipo
Scala: opciones case class Persona(nombre:String,email:Option[String])
Persona("felix",Some("
[email protected]"))
Persona("lucas",None)
Scala: excepciones def dividir(a:Int,b:Int):Option[Double]= try { Some(a/b) } catch { case ex:Exception=> ex.printStackTrace None } //> dividir: (a: Int, b: Int)Option[Double] val div=dividir(3,0) //> java.lang.ArithmeticException: / by zero
Scala: excepciones def dividir2(a:Int,b:Int):Try[Double]= Try(a/b) val div2=dividir2(3,0) //> div2 : scala.util.Try[Double] = Failure(java.lang.ArithmeticException: div2.isSuccess //> res0: Boolean = false div2 match { case Success(d)=>println(d) case Failure(ex)=>ex.printStackTrace } //> java.lang.ArithmeticException: / by zero div2.toOption //> res1: Option[Double] = None
Scala: implícitos class PlatoTipico{ val ingredientes=new ArrayBuffer[Ingrediente] } case class Ingrediente(i:String) def aumentar(ing:Ingrediente)(implicit plato:PlatoTipico)={ plato.ingredientes+=ing } implicit val silpancho=new PlatoTipico aumentar(Ingrediente("huevo")) aumentar(Ingrediente("arroz")) println(silpancho.ingredientes)
//> ArrayBuffer(Ingrediente(huevo), Ingrediente(arroz))
implicit def strToIngrediente(s:String)=Ingrediente(s) aumentar("apanado")
Scala: implícitos implicit class StringPlus(s:String){ def quitarEspacios=s.replaceAll(" ","") def codificar=Base64.encode(s.getBytes) }
"la unión es la fuerza".quitarEspacios //> res3: String = launióneslafuerza
"catecbol".codificar //> res4: Array[Byte] = Array(89, 50, 70, 48, 90, 87, 78, 105, 98, 50, 119, 61)
Scala: futuros def operacionLarga={ Thread.sleep(5000) println("terminó larga") 4 } def operacionCorta={ Thread.sleep(1) println("terminó corta") } operacionLarga operacionCorta
//> terminó larga //| res0: Int = 4 //> terminó corta
Scala: futuros val fut=Future(operacionLarga) operacionCorta //> terminó corta fut.onComplete { result => println(result) }
Future(operacionLarga) Future(operacionLarga) Future(operacionLarga)
Thread.sleep(10000) //| Success(4) //| terminó larga //| terminó larga //| terminó larga-
Scala: java interop import org.joda.time.DateTime import collection.JavaConversions._ "esta cadena".getClass
//> res0: Class[?0] = class java.lang.String
val fecha=DateTime.now //> fecha:org.joda.time.DateTime=2017-05-26T21:44:14.778+02:00 fecha.toTimeOfDay() //> res1: org.joda.time.TimeOfDay = T21:44:14.778 val javaLista=new java.util.ArrayList[String] javaLista.add("a") javaLista.add("b") javaLista.add("c")
javaLista.foreach(println)
//> a //| b //| c
javaLista.map(_.toUpperCase)
//> res5: ArrayBuffer(A, B, C)
Scala: scalatest class DemoTest extends FlatSpec with Matchers { "Una cadena " should "cumplir" in{ val s="cadena" s should not be (null) s.length shouldBe (6) s should startWith ("c") s should contain ('d') } }
Scala: sbt simple build tool name := "scala-fundamentos" organization := "jpcik" version := "0.0.1" scalaVersion := "2.11.8" libraryDependencies ++= Seq( "com.typesafe" % "config" % "1.3.1", "joda-time" % "joda-time" % "2.9.9", "org.scalatest" %% "scalatest" % "2.2.1" % "test", "junit" % "junit" % "4.12" % "test" ) resolvers ++= Seq( "typesafe" at "http://repo.typesafe.com/typesafe/releases/", Resolver.sonatypeRepo("public") )
http://www.scala-sbt.org/
Scala: IDEs: Eclipse, IntelliJ
http://scala-ide.org/
Scala: akka
http://akka.io/
Scala: play framework
https://playframework.com/
Scala: Apache Spark
https://spark.apache.org
Scala: Docs
http://docs.scala-lang.org/
Material disponible https://github.com/jpcik/tutorials
Catecbol www.catecbol.com
Capacitación Tecnológica Científica para Bolivia facebook.com/catecbol
@catecbol
Gracias
[email protected] Jean-Paul Calbimonte
La unión es la fuerza
[email protected]