s9.pdf

24
Tema 7: Programación Imperativa 1

Transcript of s9.pdf

Page 1: s9.pdf

Tema 7: Programación Imperativa

�1

Page 2: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Características de la programación imperativa Orígenes de la programación imperativa

• La programación imperativa es la forma natural de programar un computador, es el estilo de programación que se utiliza en el ensamblador, el estilo más cercano a la arquitectura del computador

• Características de la arquitectura clásica de Von Newmann:

• memoria donde se almacenan los datos (referenciables por su dirección de memoria) y el programa

• unidad de control que ejecuta las instrucciones del programa (contador del programa)

• Los primeros lenguajes de programación (como el Fortran) son abstracciones del ensamblador y de esta arquitectura, lenguajes más modernos como el BASIC o el C han continuado esta idea

�2

Page 3: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación Imperativa Características principales

• La computación se realiza cambiando el estado del programa por medio de sentencias que definen pasos de ejecución del computador

• Estado del programa modificable

• Modificación de datos

• Almacenamiento de datos en variables con valor y referencia (igualdad de valor y de referencia)

• Sentencias de control que definen pasos de ejecución

val unoDosTres = Array(“uno”,“dos”,“tres”) !unoDosTres(2) = unoDosTres(0)

def llenaArray(array: Array[String]) = { var i = 1 ! while (i < array.length) ! { array(i) = array(0) ! i += 1 } }

�3

Page 4: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Características principales Almacenamiento de datos en variables

• Todos los lenguajes de programación definen variables que contienen datos

• Las variables pueden mantener valores (tipos de valor o value types) o referencias (tipos de referencia o reference types)

• En C, C++ o Java, los datos primitivos como int o char son de tipo valor y los objetos y datos compuestos son de tipo referencia

• La asignación de un valor a una variable tiene implicaciones distintas si el tipo es de valor (se copia el valor) o de referencia (se copia la referencia)

var x = 10!var y = x!x = 20!y

var x = Array(1,2,3,4)!var y = x!x(0) = 10!x!y

Copia de valor:

Copia de referencia:

Los datos simples se copian (su valor)

Los datos compuestos

se referencian

�4

Igualdad de valor (el contenido de los datos de las variables es el mismo)Igualdad de referencia (las variables tienen la misma referencia)Igualdad de referencia => Igualdad de valor (pero al revés no)

Page 5: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Características principales Sentencias de control

• La ejecución de pasos de ejecución va modificando el contador de programa que indica la siguiente instrucción a ejecutar

• Sentencias de control:

• de secuencia: definen instrucciones que son ejecutadas una detrás de otra de forma síncrona

• de selección: definen una o más condiciones que determinan las instrucciones que se deberán ejecutar

• de iteración: definen instrucciones que se ejecutan de forma repetitiva hasta que se cumple una determinada condición

• Llamada a una función: se modifica el contador de programa �5

Page 6: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Características y pasos de ejecución

• Pasos de ejecución con la forma especial begin

• Asignación con la forma especial set!

• Datos mutables con las formas especiales set-­‐car! y set-­‐cdr!

• Todas las sentencias de la forma espec ia l se e jecu tan de fo rma secuencial, una tras otra

• Tanto en la forma especial let como en lambda y define es posible definir cuerpos de función con múltiples sentencias que se ejecutan también de forma secuencial

(begin! (display "Escribe un número: ")! (define x (read))! (display "Escribe otro: ")! (define y (read))! (define maximo (max x y))! (display (string-append "El máximo de "! (number->string x)! " y "! (number->string y)! " es "! (number->string maximo))))

(define (display-tres-valores a b c)! (display a)! (newline)! (display b)! (newline)! (display c)! (newline))

En el cuerpo de define, lambda y let

no es necesario utilizar begin

�6

Page 7: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Forma especial set!

• La forma especial set! permite asignar un nuevo valor a una variable

• La variable debe haber sido previamente creada con define

• La forma especial no devuelve ningún valor, modifica el valor de la variable usada

Sintaxis:

(set! <variable> <nuevo-valor>)

(define a 10)!(set! a (+ a 1))!a 11

No devuelve nada, modifica el valorde la variable a

(define a '(1 2 3 4))!(define b '(hola adios))!(let ((aux a))! (set! a b)! (set! b aux)))

Intercambiamos los valores de a y b utilizando una

variable auxiliar

�7

Page 8: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Formas especiales set-­‐car!  set-­‐cdr!

• En Scheme se definen las formas especiales set-­‐car! y set-­‐cdr! que permiten modificar (mutar) la parte izquierda o derecha de una pareja una vez creada

• Al igua l que set! , no devuelven ningún valor

Sintaxis:(set-car! <pareja> <nuevo-valor>)!(set-cdr! <pareja> <nuevo-valor>)

(define p (cons 1 2))!p!(set-car! p 10)!(set-cdr! p 20)!p

(1 . 2)

(10 . 20)

muta la parte izquierdamuta la parte derecha

�8

Page 9: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Efectos laterales

• La introducción de la asignación y los datos mutables hace p o s i b l e q u e S c h e m e s e comporte como un lenguaje imperativo en el que más de una variable apunta a un mismo valor y se producen efectos laterales

• Un efecto lateral se produce cuando el valor de una variable cambia debido a una sentencia en la que no aparece la variable

(define a (cons 1 2))!(define b a)!(car b)!(set-car! a 20)!(car b)

a es un dato compuesto, por lo que b referencia a

la misma pareja que ase muta la parte izquierda de a

1

20

Al mutar a, también se ha modificado b porque estaban

referenciando a la misma pareja (porque es un dato

compuesto): se produce un efecto lateral

�9

Page 10: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Igualdad de referencia y de valor: equal?  eq?

• La utilización de referencias, la mutación y los efectos laterales hace también necesario definir dos tipos de igualdades: igualdad de referencia e igualdad de valor.

• Igualdad de referencia: dos variables son iguales cuando apuntan al mismo valor: eq?

• Igualdad de valor: dos variables son iguales cuando contienen el mismo valor: equal?

• Igualdad de referencia implica igualdad de valor, pero no al revés

(define z1 '(a b))!(define z2 '(a b))!(define z3 z1)!(equal? z1 z2) !(eq? z1 z2) !(equal? z2 z3) !(eq? z2 z3)!(eq? z1 z3)

#t#f

#t#f#t

�10

Page 11: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: mutación

• Dibuja el Box & Pointer:

• Hay elementos de las parejas que son datos atómicos y otros que son referencias a otras parejas

• Mutamos el 8 por 18:

• ¿Cuál es el Box & Pointer resultante después de la instrucción?

�11

(define datos (cons 2! (cons (cons 5! (cons 8 9))! (cons 3 4))))

(set-cdr! (cdr datos) (cdr (car (cdr datos))))

(set-car! (cdr (car (cdr datos))) 18)

devuelve la pareja (8.9)muta la parte izquierda

Page 12: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables

• Al igual que set!, set-­‐car! o set-­‐cdr! , la función append! no devuelve ningún valor, sino que modifica directamente la lista que se pasa como primer parámetro

• Al modificarse la lista, todas las referencias que apuntan a ellas quedan también modificadas

• La función daría un error en el caso en que la llamáramos con una lista vacía como primer argumento

(define (append! l1 l2)! (if (null? (cdr l1))! (set-cdr! l1 l2)! (append! (cdr l1) l2)))

(define a '(1 2 3 4))!(define b '(5 6 7))!(append! a b)!a (1 2 3 4 5 6 7)

�12

Page 13: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: lista ordenada mutable

• Función mutadora insert! añade una nueva pareja a la lista, insertándola en la posición correcta modificando las referencias

• El constructor make-­‐empty-­‐olist devuelve una pareja que hace de cabecera de la lista y contiene en su parte izquierda el símbolo *olist*. Este símbolo es un convenio y podríamos sustituirlo por cualquier otro.

• La cabecera de la lista sirven para anclar la lista y definir una referencia inmutable a la misma, a la que las variables pueden apuntar. De esta forma podremos insertar elementos en primera posición de la lista.

• La función (add-­‐to-­‐olist!  item  olist) es la función clave que crea una nueva pareja con el item y la añade en el cdr de olist.

�13

Page 14: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: lista ordenada mutable

(define (make-empty-olist)! (cons '*olist* '())) !!(define (empty-olist? olist)! (null? (cdr olist)))!!(define (first-in-olist olist)! (cadr olist))!!(define (rest-of-olist olist)! (cdr olist))!!(define (add-to-olist! item olist)! (set-cdr! olist (cons item (cdr olist))))

�14

(define (insert! n olist)! (cond ((empty-olist? olist) (add-to-olist! n olist))! ((< n (first-in-olist olist)) (add-to-olist! n olist))! ((= n (first-in-olist olist)) #f) ; el valor devuelto no importa! (else (insert! n (rest-of-olist olist))) ))

Page 15: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: árbol binario ordenado

(define (make-bt dato izq der)! (list dato izq der))!!(define (make-hoja-bt dato)! (make-bt dato 'vacio-bt 'vacio-bt))!!(define (vacio-bt? btree) (equal? btree 'vacio-bt))!(define (dato-bt btree) (car btree))!(define (izq-bt btree) (car (cdr btree)))!(define (der-bt btree) (car (cdr (cdr btree))))!!(define (hoja-bt? btree)! (and (vacio-bt? (izq-bt btree))! (vacio-bt? (der-bt btree))))

En el árbol binario ordenado siempre vamos a insertar por las ramas. Podemos usar el propio nodo

raíz del árbol como el objeto al que referenciar, porque nunca va a cambiar. No hace falta definir

una cabecera como hemos hecho con la lista ordenada

La función set-­‐dato-­‐bt! modifica el valor de un dato del árbol, cambiándolo por uno nuevo.

Las funciones add-­‐to-­‐left!  y add-­‐to-­‐right! insertan (con mutación) un dato en la rama izquierda

o derecha respectivamente de un árbol binario ordenado

�15

(define (set-dato-bt! x btree)! (set-car! btree x))!!(define (inserta-izq! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cdr btree) node)))!!(define (inserta-der! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cddr btree) node)))

Page 16: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: árbol binario ordenado

(define (make-bt dato izq der)! (list dato izq der))!!(define (make-hoja-bt dato)! (make-bt dato 'vacio-bt 'vacio-bt))!!(define (vacio-bt? btree) (equal? btree 'vacio-bt))!(define (dato-bt btree) (car btree))!(define (izq-bt btree) (car (cdr btree)))!(define (der-bt btree) (car (cdr (cdr btree))))!!(define (hoja-bt? btree)! (and (vacio-bt? (izq-bt btree))! (vacio-bt? (der-bt btree))))

Utilizando las funciones anteriores, la función insert-­‐btree! inserta (con mutación) un dato en un árbol binario ordenado. Vamos recorriendo el

árbol hasta llegar a la hoja donde hay que insertar el árbol. Llamamos a la función add-­‐to-­‐right! si el dato a insertar es mayor que la hoja y a add-­‐to-­‐

left! si es menor

�16

(define (insert-btree! x btree)! (cond! ((null? btree) (make-btree x nil nil))! ((< x (datum-btree btree))! (if (empty-btree? (left-btree btree))! (add-to-left! x btree)! (insert-btree! x (left-btree btree))))! ((> x (datum-btree btree))! (if (empty-btree? (right-btree btree))! (add-to-right! x btree)! (insert-btree! x (right-btree btree))))! (else btree)))

(define (set-dato-bt! x btree)! (set-car! btree x))!!(define (inserta-izq! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cdr btree) node)))!!(define (inserta-der! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cddr btree) node)))

Page 17: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: cuadrado-­‐bt

(define (make-bt dato izq der)! (list dato izq der))!!(define (make-hoja-bt dato)! (make-bt dato 'vacio-bt 'vacio-bt))!!(define (vacio-bt? btree) (equal? btree 'vacio-bt))!(define (dato-bt btree) (car btree))!(define (izq-bt btree) (car (cdr btree)))!(define (der-bt btree) (car (cdr (cdr btree))))!!(define (hoja-bt? btree)! (and (vacio-bt? (izq-bt btree))! (vacio-bt? (der-bt btree))))

�17

(define (cuadrado-bt! btree)! (if (not (vacio-bt? btree))! (begin! (set-dato-bt! (cuadrado (dato-bt btree)) btree)! (cuadrado-bt! (izq-bt btree))! (cuadrado-bt! (der-bt btree)))))

(define (set-dato-bt! x btree)! (set-car! btree x))!!(define (inserta-izq! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cdr btree) node)))!!(define (inserta-der! x btree)! (let ((node (make-hoja-bt x)))! (set-car! (cddr btree) node)))

Usamos la función set-­‐dato-­‐bt! para elevar todos los datos de un árbol a su cuadrado

Ejercicio: define la función cuadrado-­‐tree para árboles genéricos

Page 18: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: tabla hash

• Tabla hash definida mediante una lista de asociación formada por parejas de clave y valor

• La función de Scheme assq recorre la lista de asociación y devuelve la pareja que contiene el dato que se pasa como parámetro como clave, utilizando la igualdad eq?

(define l-assoc (list (cons 'a 1) ! (cons 'b 2) ! (cons 'c 3)))

(assq 'a l-assoc) --> (a.1)!(assq 'b l-assoc) --> (b.2)!(assq 'c l-assoc) --> (c.3)!(assq 'd l-assoc) --> #f!(cdr (assq 'c l-assoc)) --> 3

(define h "hola")!(define l '(1 2))!(define l-assoc (list (cons h 1) (cons l 2) (cons 'c 3)))!(assq "hola" l-assoc) --> #f!(assq h l-assoc) --> ("hola".1)

�18

Page 19: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Estructuras de datos mutables: tabla hash

• Implementación de la tabla hash con cabecera, utilizando listas de asociación

(define (make-table)! (list '*table*))!!(define (get key table)! (let ((record (assq key (cdr table))))! (if (not record)! #f! (cdr record))))!!(define (put key value table)! (let ((record (assq key (cdr table))))! (if (not record)! (set-cdr! table! (cons (cons key value)! (cdr table)))! (set-cdr! record value)))! 'ok)

(define tab (make-table))!(put 'a 10 tab)!(get 'a tab)!(put 'b '(a b c) tab)!(get 'b tab)!(put 'a 'ardilla tab)!(get 'a tab)

constructor de la tabla hash

get: busca en la lista de asociación si está la clave, si está devuelve su valor asociado, y si no está devuelve #f

put: busca en la lista de asociación si está la clave, si está modifica su valor por value y si no está, crea una

nueva pareja key-value y la almacena al final de la tabla

�19

Page 20: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Ejemplo de mutación con listas de asociación

• Implementar un procedimiento regular-­‐>assoc! que transforme una lista regular en una lista de asociación sin crear nuevas parejas. La lista regular (k1 v1 k2 v2 k3 v3 ...) deberá convertirse en la lista de asociación ((k1 . v1) (k2 . v2) (k3 . v3) ...)

(define my-list (list 'a 1 'b 2 'c 3))!my-list ;--> (a 1 b 2 c 3)!(regular->assoc! my-list)!my-list ;--> ((a . 1) (b . 2) (c . 3))

�20

Page 21: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Ejemplo de mutación con listas de asociación

Por un lado, no podemos crear nuevas parejas, por lo que cada pareja en el primer diagrama corresponde a una pareja particular en el segundo diagrama. Por otro lado, no podemos modificar la primera pareja de la lista (porque perderíamos la ligadura de la variable my-list), por lo que esa pr imera pareja t iene que permanecer en el primer lugar. Por otra parte, a y 1 van a formar parte del mismo par en la lista de asociación

�21

Page 22: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Ejemplo de mutación con listas de asociación

(define (manejar-dos-parejas! p)! (let ((key (car p))) ! (set-car! p (cdr p)) ! (set-cdr! p (cdr (car p))) ! (set-cdr! (car p) (car (car p))) ! (set-car! (car p) key)))

let para guardar el valor actual del (car p), ese valor será la clave de la primera pareja de la lista de asociación; necesitamos almacenarlo para no perderlo

completamos el problema poniendo la clave que habíamos guardado, en el car de la pareja azul

cambiamos el cdr de la pareja en azul al car de la misma pareja. Hacemos ésto porque en una lista de asociación, los valores se guardan en los cdrs y las claves en los cars

cambiamos el cdr de p para que apunte al cdr de la pareja en azul

cambiamos el car de p para que apunte a la siguiente pareja (la azul)

Reordenamos el diagrama para verlo más claro:

(define (regular->assoc l)! (if (null? l) ! 'okay! (begin (manejar-dos-parejas! l)! (regular->assoc! (cdr l)))))

Función que maneja dos parejas:

Función que maneja toda la lista:

�22

Page 23: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Clausuras con estado local mutable

(define (make-contador i)! (let ((x i))! ! (lambda ()! !! (set! x (+ x 1))! !! x)))

!El estado se mantiene entre distintas invocaciones a f (diferencia con el paradigma funcional)

Se crean tantos ámbitos locales como invocaciones a make-contador

(define f (make-contador 4))!(f) -> 5!(f) -> 6!(define h (make-contador 10))!(define g (make-contador 100))!(h) -> 11!(h) -> 12!(g) -> 101!(g) -> 102

�23

Combinando closures y programación imperativa es posible definir estado local asociado a funciones (una combinación que representa un paso hacia la programación orientada a objetos)

Page 24: s9.pdf

Lenguajes y Paradigmas de Programación. Universidad Alicante. DCCIA. Curso 2013-2014. Cristina Pomares, Domingo Gallardo

Programación imperativa en Scheme R5RS Clausuras con estado local mutable y mensajes

• Es posible acercarnos un poco más a la programación orientada objetos si hacemos que la clausura reciba un símbolo (un mensaje) y ejecute distinto código en función del mensaje que recibe.

• Vamos a cambiar el ejemplo anterior para que la clausura pueda hacer dos cosas:

• Si recibe el símbolo ‘get devolver el valor del contador

• Si recibe el símbolo ‘inc incrementar el contador y devolver su valor

(define (make-contador i)! (let (( x i))! (lambda (msg)! (cond! ((equal? msg 'get) x)! ((equal? msg 'inc) ! (begin ! (set! x (+ x 1))! x))! ((equal? msg 'dec)! (begin ! (set! x (- x 1))! x))! (else (error "Mensaje desconocido"))))))

(define a (make-contador 10))!(a ‘inc) -> 11!(a ‘dec) -> 10!(a ‘get) -> 10

�24