Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
Tema 6: Programación funcional en Scala
Sesión 19: Programación funcional en Scala (3)
martes 12 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.
martes 12 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:
• Ordenación de una lista:
martes 12 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:
• Ordenación de una lista:
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)
martes 12 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:
• Ordenación de una lista:
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)
def sort(lista: List[Int]): List[Int] = if (lista.isEmpty) Nil else insert(lista.head, sort(lista.tail))
martes 12 de abril de 2011
Funciones sobre listas
• Reverse-list:
martes 12 de abril de 2011
Funciones sobre listas
• Reverse-list:
def reverse(l: List[Int]) : List[Int] = if (l == Nil) l else reverse(l.tail) ::: List(l.head)
martes 12 de abril de 2011
Cadenas
• El tipo de Scala es String y se convierte en la clase de Java java.lang.String
• Al igual que las listas son inmutables
• Concatenación con el operador +
• Funciones head, tail, charAt
"hola" + "adios" --> "holaadios"
"hola".head --> h"hola".tail -->"ola""hola".charAt(0) --> 'h'
martes 12 de abril de 2011
Tuplas
• Scala permite construir tuplas de n elementos de distinto tipo
• Es un tipo también inmutable
• La forma de definir una tupla de n tipos es: (tipo1, tipo2,..., tipoN)
• Métodos de acceso al elemento de la tupla ._1, ._2, …
• Ejemplo con una tupla de tres elementos:
val miTupla = (99, "Hola", true)println(miTupla._1)println(miTupla._2)println(miTupla._3)
martes 12 de abril de 2011
Tuplas
• Muy útiles para funciones que tienen que devolver más de un elemento:
martes 12 de abril de 2011
Tuplas
• Muy útiles para funciones que tienen que devolver más de un elemento:
def sumaCadenas(s1: String, s2: String): (String, Int) = (s1+s2, s1.length+s2.length)
martes 12 de abril de 2011
Ámbito de variables
• Una vez definida una variable en un ámbito no podemos volver a definirla
• Sería un error el siguiente script:
• Sí es posible hacerlo en el intérprete, porque cada evaluación de una expresión crea una nuevo ámbito
val a = 1val a = 2 // errorprintln(a)
martes 12 de abril de 2011
Ámbito de variables
• Podemos crear un ámbito interior utilizando llaves:
• Podemos utilizar funciones locales que definen su propio ámbito:
val a = 1;{ val a = 2; println(a)}println(a)
def function1(x : Int) = { def function2(y: Int) = { x*y } function2(3)}function1(2)
martes 12 de abril de 2011
Funciones como objetos de primera clase
• En Scala las funciones son también objetos de primera clase
• Podemos:
• Definir variables y parámetros de tipo función
• Almacenar funciones en estructuras de datos como listas o arrays
• Construir funciones en tiempo de ejecución (closures) y devolverlas como valor de retorno de otra función
martes 12 de abril de 2011
Ejemplo: sumatorio
• La diferencia con Scheme es que Scala es un lenguaje tipeado y hay que definir el tipo de la función que se pasa como parámetro
• La función f que se pasa como primer parámetro de sum debe recibir un entero y devolver un entero
• Si pasamos otro tipo de función, Scala detecta el error de tipos
def square(x: Int): Int = x * x
def sum(f: Int => Int, a:Int, b:Int): Int = if (a>b) 0 else f(a) + sum(f, a+1, b)
martes 12 de abril de 2011
Funciones anónimas
• Al igual que en Scheme con la forma especial lambda, en Scala podemos definir funciones anónimas creadas en tiempo de ejecución
• La función square anterior se podría definir de forma anónima como:
• Podemos definirla como parámetro de sum y no hace falta definir el tipo de las variables, porque Scala lo infiere a partir del tipo del primer parámetro:
•
(x: Int) => x * x
sum(x => x * x, a, b)
martes 12 de abril de 2011
Funciones anónimas
• Una notación más concisa utiliza subrayados como huecos (placeholders) de los parámetros de la función:
• Es equivalente a:
sum(_+2, a, b)
sum(x => x+2, a, b)
martes 12 de abril de 2011
Variables de tipo función
• Al igual que en Scheme, podemos asignar funciones a variables:
• Para asignar una función ya definida a una variable hay que utilizar la sintaxis de huecos (placeholders) para indicar al compilador que no tiene que aplicar la función:
def suma3(a: Int, b: Int, c: Int) = a + b + cval f = suma3 _ f(1,2,3) --> 6
val f = (s:String) => s + “adios”f(“hola”)
martes 12 de abril de 2011
Variables de tipo función
• Podemos almacenar funciones en listas, pero todas las funciones deben tener el mismo perfil:
def suma3(a: Int, b: Int, c: Int) = a + b + c def mult3(a: Int, b: Int, c: Int) = a * b * c
val listaFuncs = List(suma3 _, mult3 _)
val f = listaFuncs.headf(1,2,3)
martes 12 de abril de 2011
Variables de tipo función
• Ejemplo de función que toma una lista de funciones de un argumento y las aplica:
def aplicaLista (lista: List[(Int) => Int], x: Int): Int = if (lista.length == 1) lista.head(x) else lista.head(aplicaLista(lista.tail,x))
def mas5(x: Int) = x+5def por8(x: Int) = x*8val l = List(mas5 _, por8 _)aplicaLista(l, 10)
martes 12 de abril de 2011
Variables de tipo función
• Es posible utilizar la sintaxis de los huecos para proporcionar algunos de los argumentos y dejar libres otros.
• Con la siguiente expresión definimos una variable de tipo función de un argumento a partir de una función anterior
val g = suma3(1, _: Int, 10)
• Es posible utilizar la sintaxis de los huecos para proporcionar algunos de los argumentos y dejar libres otros.
• Con la siguiente expresión definimos una variable de tipo función de un argumento a partir de una función anterior
martes 12 de abril de 2011
Devolviendo funciones anónimas
• Las funciones pueden crearse y ser devueltas por otras funciones
• ¿Cómo declararías el tipo devuelto por la función makeSumador(Int)?
def makeSumador(k: Int) = (x: Int) => x + kval f = makeSumador(10)val g = makeSumador(100)f(4)g(4)
martes 12 de abril de 2011
Closures
• Al igual que en Scheme, las funciones definidas en un ámbito mantienen el acceso a ese ámbito y pueden usar los valores allí definidos.
• Llamamos closure a estas funciones
• En el ejemplo siguiente, el ámbito en el que se crea la función devuelta contiene la variable i (el argumento de makeClosure) y la variable valor x declarada con el valor 5
def makeClosure(i : Int) : Int => Int = { val x = 5 (j : Int) => i + j + x}val returnedFuncion : Int => Int = makeClosure(10)println(returnedFuncion) //=> <function>println(returnedFunction(20)) //=> 35, porque 10 + 20 + 5 = 35
martes 12 de abril de 2011