Programación funcional en Scala

Anuncio
Tema 6: Programación funcional en Scala
Sesión 18: Programación funcional en Scala
jueves 7 de abril de 2011
Referencias
• Programming in Scala. Martin Odersky, Lex Spoon, Bil Venners. Ed. Artima.
• Programming Scala. Dean Wampler, Alex Payne. Ed. O'Reilly.
• Scala by Example. Martin Odersky. November 2010.
• A Scala Tutorial for Java programmers. Michel Schinz, Philipp Haller.
November 2010.
• The Scala Language Specification. Martin Odersky. November 2010.
jueves 7 de abril de 2011
Expresiones y funciones simples en el intérprete
• El intérprete analiza las expresiones, realiza las inferencias de tipos
necesarias y evalua la expresión:
scala> 5 + 2 * 3
scala> 5 + 2.0 * 3
scala> "hola" + " mundo!"
jueves 7 de abril de 2011
Variables mutables e inmutables
• Scala diferencia entre variables inmutables (declaradas con val y variables
mutables var)
• Es recomendable utilizar siempre que podamos variables inmutables (val),
esto refuerza el carácter funcional de nuestros programas
• Las variables son estrictamente tipeadas, aunque no es necesario declarar el
tipo porque Scala puede inferirlo
jueves 7 de abril de 2011
Variables mutables e inmutables
scala> val msg = "Hola mundo!"
msg: java.lang.String = Hola mundo!
scala> var saludo = "Hola mundo!"
saludo: java.lang.String = Hola mundo!
scala> saludo = "Hasta luego!"
saludo: java.lang.String = Hasta luego!
scala> saludo = 3.0
<console>:5: error: type mismatch;
found
: Double(3.0)
required: java.lang.String
jueves 7 de abril de 2011
Variables mutables e inmutables
• ¡Cuidado! El intérprete permite declarar varias veces la misma variable. Cada
ejecución de una nueva sentencia crea un nuevo ámbito en el que se define
la nueva variable. Las variables anteriores se pierden. Esto no es correcto en
un programa; una variable sólo se puede declarar una vez.
• Las variables declaradas con val no pueden ser reasignadas. Esto no impide
que cambie el valor del objeto que contienen (en el caso de estar en el
paradigma imperativo). Ejemplo:
scala> val a = Array(1,0,0)
a: Array[Int] = Array(1, 0, 0)
scala> a(1) = 1
scala> a
res42: Array[Int] = Array(1, 1, 0)
jueves 7 de abril de 2011
Tipos de datos básicos
• Aunque hablemos de tipos de datos, en Scala todos los tipos de datos son
clases
• Algunos tipos de datos y formas de inicializarlos:
Tipo de dato
Rango
Ejemplo
Byte
Short
Long
Int
Char
Float
Double
Boolean
String
8-bit con signo
16-bit con signo
64-bit con signo
32-bit con signo
16-bit sin signo
32 bit flotante con signo
64 bit flotante con signo
true o false
secuencia de caracteres
38
23
3434332
70
A’
1.234
1.234
true
“hola”
• El API completo de Scala se puede consultar en http://www.scala-lang.org/
api/current/index.html
jueves 7 de abril de 2011
Operadores
• Aritméticos: + - = * %
• Relacionales: < <= > >= != ==
• Lógicos: && || !
jueves 7 de abril de 2011
def para dar nombre a expresiones
• def es una primitiva declarativa: le da un nombre a una expresión, pero no la
evalua
• La evaluación se realiza cuando se llame al identificador
def t = 8 / 0 --> No da error
t --> al evaluar t, error división por cero
• En el caso de val o var la evaluación se realiza antes de hacer la asignación
val t = 8 / 0 --> error
jueves 7 de abril de 2011
¿Cuándo se evalúan las variables en un def?
• Las variables en una expresión definida por def se evaluan cuando se invoca
al identificador definido:
var x = 10
def t = x / 5
var x = 5
t -> 1
jueves 7 de abril de 2011
def para definir funciones
• Sintaxis:
def <nombre_funcion>(<parametro1:tipo1>,...):<tipo_resultado>={
<cuerpo de la función>
}
• Ejemplo:
def max(x: Int, y: Int): Int = {
if (x > y) x
else y
}
max: (Int,Int)Int
jueves 7 de abril de 2011
def para definir funciones
• Las llaves son opcionales si el cuerpo tiene una sóla sentencia
• El tipo de retorno es opcional si Scala puede inferirlo (no aplicable a
funciones recursivas)
scala> def max2(x: Int, y: Int) = if (x > y) x else y
max2: (Int,Int)Int
• La función se evalúa cuando se invoca:
scala> max2(3, 5)
res6: Int = 5
• Los ejemplos anteriores en los que se definían expresiones se pueden
interpretar de esta manera: como una definición de una función de una única
sentencia (la expresión) que se evalua cuando se invoca
jueves 7 de abril de 2011
Una función que no devuelve nada
• Por ahora todas las funciones que vamos a definir van a estar en el
paradigma funcional, siempre devolverán algún valor
• Sin embargo Scala es también procedural:
scala> def hola() = println("Hola mundo")
hola: ()Unit
• La función hola no devuelve ningún valor; la clase Unit es similar al tipo
void de Java
jueves 7 de abril de 2011
Expresiones condicionales: if
• if: condicional; cuidado con el fin de línea si no utilizamos llaves
• Correcto:
• Incorrecto:
• Correcto:
jueves 7 de abril de 2011
def abs(x: Double) = if (x >= 0) x else -x
def abs(x: Double) =
if (x >= 0) x
else -x
def abs(x: Double) =
if (x >= 0) x else
-x
Expresiones if anidadas
def entre(x: Double, x1: Double, x2: Double) =
if (x < x1) false else
if (x > x2) false else
true
jueves 7 de abril de 2011
Expresiones condicionales: match
• Similar al cond de Scheme
var myVar = 3;
myVar match {
case 1 => "Uno"
case 2 => "Dos"
case 3 => "Tres"
case 4 => "Cuatro"
}
• El “default” se escribe como _
case _ => “otro caso”
jueves 7 de abril de 2011
Funciones recursivas
• El típico ejemplo de función recursiva: factorial en Scala
def factorial(x: Long): Long =
if (x == 0) 1 else x * factorial(x - 1)
• Máximo común divisor recursivo:
def gcd(x: Long, y:Long): Long =
if (y == 0) x else gcd(y, x % y)
jueves 7 de abril de 2011
Listas
• La clase List de Scala permite definir listas
• Al igual que Scheme son inmutables y tienen una estructura recursiva
• A diferencia de Scheme son estrictamente tipeadas
val
val
val
val
fruit = List("apples", "oranges", "pears")
nums = List(1, 2, 3, 4)
diag3 = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
empty = List()
jueves 7 de abril de 2011
Operador cons
• Funciona igual que en Scheme, produce una nueva lista añadiendo un nuevo
elemento a su cabeza
• Se define con 4 puntos ::
val dosTres = List(2, 3)
val unDosTres = 1 :: dosTres
• La lista vacía se define con el identificador Nil
val unoDosTres = 1 :: 2 :: 3 :: Nil
val fruit = "apples" :: ("oranges" :: ("pears" :: Nil))
val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
val diag3 = (1::(0::(0::Nil)))::
(0 :: (1 :: (0 :: Nil))) ::
(0 :: (0 :: (1 :: Nil))) :: Nil
val empty = Nil
val nums = 1::2::3::4::Nil
jueves 7 de abril de 2011
Operaciones básicas sobre listas
• head: devuelve el primer elemento de la lista
• tail: devuelve el resto de la lista
• isEmpty: predicado que comprueba si la lista es vacía
• ::: operador similar a append que concatena dos listas
jueves 7 de abril de 2011
Funciones sobre listas
• Con las operaciones previas se pueden definir funciones similares a las que
vimos en Scheme
• Inserción en una lista ordenada:
jueves 7 de abril de 2011
Funciones sobre listas
• Con las operaciones previas se pueden definir funciones similares a las que
vimos en Scheme
• Inserción en una lista ordenada:
def insert(x: Int, lista: List[Int]) : List[Int] =
if (lista.isEmpty) x :: Nil else
if (x < lista.head) x :: lista else
lista.head :: insert(x, lista.tail)
jueves 7 de abril de 2011
Descargar