Tutorial de OCaml capitulo 2.

Escrito el 27 Julio, 2001 – 11:25 | por storm | 4.530 lecturas

Esta es la segunda entrega de nuestro tutorial exclusivo de Ocaml, un lenguaje extremadamente cool, en esta entrega tipos de datos agregados, listas, tuplas pattern matching y muchas funciones.

Tipos agregados:casi todos los lenguajes de programacion tienen tipos de datos que pueden clasificarse en dos tipos: atomicos y agregados. Los tipos atomicos basicos son los enteros, chars, strings, etc. Los tipos agregados son las colecciones de datos y el tipo agregado mas popular es el “vector”. Ocaml tiene varios tipos agregados, algunos de los cuales como por ejemplo las listas y las tuplas analizaremos en este capitulo de nuestro tutorial.

Tuplas:
Una tupla es una coleccion ordenada y heterogenea de valores separados por comas. En Ocaml una tupla puede escribirse de la forma:

let t = 1, "Hola";;

En donde creamos una tupla de 2 elementos, un entero y un string. Las tuplas puede ser desconstruidas usando simplemente una asignacion let con tantos valores como elementos tenga la tupla:

let t = 1,"Hola";;let x,y = t;;

En donde x tomara el valor entero 1 e y tomara el string “Hola”. Si queremos asignar a dos valores una tupla de mas de 2 elementos obtendremos un error. Una curiosidad de Ocaml es que la asignacion let multiple es simultanea, por ejemplo:

let x = 4;;let y = 9;;let x,y = y,x;;

Luego de esta asignacion x es 9 e y es 4. Los valores fueron swappeados sin usar una variable auxiliar porque let hace la asignacion en forma simultanea.

Las tuplas son usadas por ejemplo para definir puntos cartesianos.

Listas:Una lista es una secuencia de valores homogenea. Es decir que todos los elementos de la lista deben ser del mismo tipo, una lista se denota de la forma:

let l = "Hola" :: "Juan" :: [];;

Donde [] es la lista “vacia” y :: se usa como operador de construccion de listas. Al inicializar una lista es necesario terminarla con la lista vacia para que el compilador sepa que se trata de una lista, sino da un error. Las listas pueden ser desconstruidas usando pattern matching al igual que las tuplas. Veamos una funcion que suma todos los elementos de una lista de enteros

let rec sum = function  [] -> 0  |i :: l -> i + sum l;;

Como vemos hay dos patterns que son basicos: si la lista es vacia la suma es cero, si la lista es i :: l entonces es i sumado a la suma de l, la desconstruccion i :: l es sumamente util ya que hace que el primer elemento se coloque en “i” y todo lo que queda de la lista en “l”, es una desconstruccion en cabeza y cola y se usa en una enorme cantidad de funciones recursivas que manipulan listas. Como vemos la funcion suma solo puede aplicarse a una lista de enteros pues se usa la funcion “+” que es para enteros.

Polimorfismo:Es posible definir en Ocaml funciones polimorficas, es decir funciones que reciben un parametro de “algun tipo” y hacen algo con el, una funcion polimorfica tipica es la funcion identidad:

let identidad x = x;;

Como vemos esto genera una funcion de tipo: val identity : ‘a -> ‘a = . Donde ‘a quiere decir “algo de cualquier tipo”. El polimorfismo puede usarse para definir funciones para manipular listas que se apliquen a listas de cualquier tipo de elementos. Por ejemplo la funcion “pertenece” que dice si un elemento x pertenece a una lista.

let rec pertenece x l =match l with  [] -> false  |i :: j -> x=y || pertenece x l;;

Como vemos si la lista es vacia devolvemos falso y sino devolvemos que x es la cabeza o calculamos la pertenencia de x a la cola de la lista. El uso del operador logico || es aqui muy importante ya que en Ocaml si la primera parte de un or da verdadero no se evalua la segunda y eso hace que nuestra funcion funcione correctamente ya que si aparece x en la cabeza de la lista entonces no se lo busca en la cola. Pertenece es una funcion polimorfica ya que funciona para listas de cualquier tipo.

La siguiente funcion permite aplicar una funcion a cada elemento de una lista.

let rec map f l =match l with[] -> []|i :: j -> f i || map f j;;

Con lo cual podemos hacer:

let li= [1;2;3;4];;map succ li;;

Que devuelve [2;3;4;5]. Notar otra forma de definir una lista usando corchetes y los elementos separados por punto
y coma, que es una forma bastante mas practica de inicializar una lista.La funcion del lenguaje succ devuelve el elemento siguiente de un entero (el incremento), como la lista es de enteros es posible “mapear” la funcion succ a toda la lista.

Vectores asociativos: quienes esten acostumbrados a Perl o PHP pueden extrañar los vectores asociativos, que son vectores de pares tipo clave-valor. En Ocaml este tipo de estructura se maneja usando listas, por ejemplo:

let claves = ["juan","hola"; "pepe","1098" ]

Es facil a partir de una lista de este tipo construir funciones que devuelvan,por ejemplo el valor de una clave:

let rec getval key l =match l with[] -> ""|(clave,valor) :: j -> if key=clave then valor else getval key j;;

En la funcion notar como la lista es descontruida en una cabeza de tipo (clave,valor) y una cola y si en la cabeza
la clave coicide con la buscada devolvemos el valor y en caso contrario buscamos en la cola. En este ejemplo introducimos la instruccion “if” que es muy simple de la forma “if expr then codigo else codigo”. La unica salvedad del if es que siempre debe especificarse el “else” y que la rama del else debe devolver algo del mismo tipo que lo que devuelve la rama del if.

El manejo de listas es extremadamente importante, el uso de funciones recursivas, listas y pattern matching permite la construccion de todo tipo de funciones extremadamente poderosas y hasta un parser completo de un lenguaje puede implementarse usando solamente estas cosas.

Ejercicios:

  1. Programar una funcion que devuelva la interseccion entre dos listas de cualquier tipo.
  2. Programar una funcion que devuelva la union entre dos listas de cualquier tipo.
  3. Programar una funcion que ordene una lista de cualquier tipo.
  4. Programar una funcion que elimine un cierto elemento de una lista
  5. Programar una funcion que calcule el producto interno de dos listas de enteros, si tienen distinta cantidad
    de elementos debe levantar una excepcion.
  6. Programar una funcion que invierta el orden de los elementos de una lista (que la de vuelta bah…)
  7. En programacion funcional se define la funcion “redux” como una funcion que recibe una funcion binaria y
    una lista y lo que hace es aplicar la funcion a los dos ultimos elementos de la lista y reemplazarlos por el
    valor devuelto por la funcion y asi recursivamente hasta quedarse con un solo elemento que devuelve. Ejemplo:
    Redux “-” [1;2;3;4] reduce la lista a [1;2;-1] luego a [1;3] y luego a [-2] que es el valor final. Programar
    la funcion Redux en Ocaml para listas de cualquier tipo.

A continuacion:En la proxima entrega vamos a analizar la creacion de nuevos tipos de datos definidos por el usuario en Ocaml, como por ejemplo arboles, colas y cosas por el estilo. Vamos a ver como el lenguaje es extremadamente poderoso para este tipo de cosas.

You must be logged in to post a comment.

Buscar: