Ir arriba

Lenguaje: HASKELL

HASKELL es un lenguaje funcional propuesto por D. Turner en 1985, consistente en un conjunto de declaraciones de ecuaciones recursivas, donde:

Se crea para el campo de la inteligencia artificial y sus campos secundarios del cálculo simbólico, pruebas de teoremas, sistemas basados en reglas y procesamiento del lenguaje natural.
Como programación funcional, sus cálculos se ven como una función matemática que hacen corresponder entradas y salidas.

No hay noción de posición de memoria y por tanto, necesidad de una instrucción de asignación.
Los bucles se modelan a través de la recursividad ya que no hay manera de incrementar o disminuir el valor de una variable.

Los lenguajes funcionales soportan el concepto de variable, asignación y bucle.
Quien programó una hoja de cálculo, especifica cada celda en terminos de los valores de otras celdas.
El objetivo es que debe ser calculado y no en como debe calcularse.
Por ejemplo:
- No especificamos el orden en el que las celdas serán calculadas, en cambio obtenemos el orden que garantiza que la hoja de cálculo puede calcular las celdas respetando las dependencias.
- No indicamos a la hoja de cálculo como manejar la memoria, en cambio esperamos que nos presente un plano de celdas, aparentemente infinito, pero que solo utiliza la memoria de las celdas que están actualmente en uso.
- Especifica el valor de una celda por una expresión (cuyas partes pueden ser evaluadas en cualquier orden), en lugar de una secuencia de comandos que calculan los valores
Los programas son más fáciles de diseñar, de escribir, de mantener; ofrece menos control sobre la máquina. La función en Haskell consiste en ecuaciones de la forma:

Los mecanismos para escribir la parte derecha en Haskell son:

Convenios sintácticos
Lenguaje: H A S K E L L
  • Haskell es un lenguaje funcional puro
  • Haskell no es un lenguaje muy rápido, pero se prioriza el tiempo del programador sobre el tiempo de computación.
  • Haskell es un lenguaje de programación con tipos polimórficos, con evaluación perezoso (lazy), y puramente funcional, muy diferente a otros lenguajes imperativos.
  • El lenguaje toma el nombre de Haskell BrooksCurry (1900-1982 Millis, Massachusetts, USA), cuyos trabajos en lógica matemática sirvieron como base a los lenguajes funcionales.
  • Haskell está basado en el cálculo lambda, de aquí el símbolo l (lambda) que aparece en el logo.

Evaluación PEREZOSA o LENTA (Lazy)
No se evalúa ningún elemento en ninguna función hasta que no sea necesario.
Las listas se almacenan internamente en un formato no evaluado La evaluación perezosa consiste en utilizar paso por nombre y recordar los valores de los argumentos ya calculados para evitar recalcularlos.

También se denomina estrategia de pasos de parámetros por necesidad.

Con una estrategia no estricta de la expresión doble (doble 3), la expresión (3 + 3) se calcula dos veces.
Definimos la función cuadrado:
cuadrado :: Integer →Integer
cuadrado x = x * x


En un lenguaje funcional se pueden definir funciones las cuales se usan en una expresión y cuyo valor tiene que ser calculado.
Para calcular el valor de una expresión se necesita un programa que entienda las definicio- nes de las funciones.
Tal programa se llama intérprete.

Tal intérprete analiza primero las funciones estándar, cuyas definiciones están en el fichero prelude (preludio), que se examina antes de definir nuevas funciones.
Finalmente, el intérprete comunica que se puede teclear. Type :? for help Prelude>
El signo de interrogación indica que el interprete esta listo para calcular el valor de una expresión.

En el prelude están definidas, entre otras, las funciones aritméticas.
Se puede usar el interprete como calculadora. Prelude> 5+2*3
11
(5 reductions, 9 cells) Prelude>
El interprete:

  • Calcula el valor de la expresión: 11 que resulta de 5 + ( 2 x 3 ) = 5 + 6
  • Indica que para el calculo usó: 5 reductions: Medida para el tiempo utilizado
  • 9 cells: Medida para la memoria utilizada.
  • Prelude>, indica que el interprete esta listo para el próximo cálculo.

NOMBRES DE FUNCIONES Y PARÁMETROS:
Empiezan con minúscula luego pueden seguir con minúsculas, mayúsculas, ó números, y los símbolos ’ _.
Ej:
f sum w5 w’ tot_de_Alumnos nombreAlumno

PALABRAS RESERVADAS: No deben usarse para definir funciones:
Case, class, data, else, if, in, infix, infixl, infixr, instance, let, of, primitive, then, type, where
OPERADORES:

  • Símbolos para formar operadores: : # $ % & * + - = . / \ < > ? ! @ ^ |
  • Operadores permitidos: + ++ && || <= == /= . // $ @@ -*- \ / / \ ... <+> ? :->
FUNCIONES SOBRE NÚMEROS:
Operaciones primitivas, para números reales:
  • sqrt Raíz cuadrada
  • sin Seno trigonométrico
  • log Logaritmo natural
  • exp Exponente (e-elevado-a)
  • fromInteger Convierte entero a numero real
  • round Redondear un numero real a un entero
OPERADORES BOOLEANOS:
  • < Menor que
  • > Mayor que
  • <= Menor o igual que
  • >= Mayor o igual que
  • == Igual a
  • /= Distinto de.
  • Ejemplos: Prelude>1<2 True Prelude> 2<1 False

FUNCIONES SOBRE LISTAS

  • length: Determina el tamaño de una lista.
  • sum: Suma números de la lista.
  • ++ : Concatena dos listas en una sola.
  • null: Comprueba si la lista esta vacía.
  • take: Tiene dos parámetros: un numero y una lista. Si el numero es n, el resultado es una lista con los primeros n elementos de la lista.
  • sort: Ordena los elementos de menor a mayor.
  • reverse: Ordena los elementos de la lista en el orden inverso.

EL ENTORNO HUGS
Sigue el modelo de una calculadora donde se establece una sesión interactiva entre el ordenador y el usuario.

  • El sistema muestra un prompt Prelude> y espera a que el usuario introduzca una expresión inicial y presione < RETURN >.
  • Cuando la entrada se ha completado, el sistema evalúa la expresión e imprime su valor antes de volver a mostrar el prompt para esperar a que se introduzca la siguiente expresión. Ejemplos:
El valor 40 puede generarse introduciendo en prelude (2+3)*8 Prelude>(2+3)*8
La lista de enteros desde 1 hasta 10, y sum es una función estándar
que devuelve la suma de una lista de enteros:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55

Prelude> sum[1..10] 55


El usuario puede definir sus propias funciones y guardarlas para que el sistema pueda utilizarlas en la evaluación, que consiste en tomar una expresión e ir transformándola aplicando las definiciones de funciones, hasta que no pueda transformarse más. La expresión resultante se denomina representación canónica y es mostrada al usuario. Ejemplos
  • Llamada por valor:
    Se evalúa los argumentos antes de llamar a la función, y se asocia con la evaluación ansiosa.
    cuadrado (3+4) = { evaluando la suma } cuadrado 7 = { utilizando la definición cuadrado x = x * x } 7 * 7 = { evaluando la multiplicación } 49
  • Llamada por nombre: Se utiliza la definición de la función antes de evaluar los argumentos
    y está asociado a la evaluación perezosa. 
    
      cuadrado (3+4)
      =                                          { utilizando la definición cuadrado x = x * x }
      (3+4) * (3+4) 
      =                                          { evaluando la parte izquierda de la multiplicación }
      7 * (3+4)       
      =                                          { evaluando la parte derecha de la multiplicación }
      7 * 7         
      =                                          { evaluando la multiplicación }
      49            
    
Valores, Tipos, Expresiones
  • Los valores son entidades abstractas que podemos considerar como la respuesta a un calculo 5 -1 8
  • Cada valor tiene asociado un tipo (< valor > :: < tipo >) 2 :: Int Int = {...-3,-2,-1,0,1,2,3...}
  • Las expresiones son terminos construidos a partir de valores (2*3)+(4-5)
  • La reducción o evaluación de una expresión consiste en aplicar una serie de reglas que transforman la expresión en un valor (2*3)+(4-5)
  • Un valor es una expresión irreducible
  • Toda expresión tiene un tipo: el tipo del valor que resulta de reducir la expresión (Sistema Fuertemente Tipado). (2*3)+(4-5) :: Int
  • El tipo de una expresión debe establecerse en tiempo de compilación sin evaluar la expresión (Tipado Estático)
  • El compilador calcula el tipo de una expresión, normalmente, sin ninguna anotación del programador (Inferencia de Tipos)
  • Las funciones también son valores (y por lo tanto tendrán tipo)

Tipos Basicos

Tipos Básicos

El sistema de tipos es utilizado para detectar errores en expresiones y definiciones de función, para ello, cada tipo tiene asociadas un conjunto de operaciones que no tienen significado para otros tipos, por ejemplo, se puede aplicar la función (+) entre enteros pero no entre caracteres o funciones.

Como Haskell permite asociar un único tipo a toda expresión bien formada, es un lenguaje fuertemente tipado; así, cualquier expresión que no pueda asociarse a un tipo será rechazada como incorrecta antes de la evaluación.

El análisis tiene dos fases:

INFORMACIÓN DE TIPO
Además de las definiciones de función, se puede incluir información de tipo mediante una expresión de la forma A : : B para indicar al sistema que A es de tipo B. Ejemplo: cuadrado:: Int -> Int Indica que la función cuadrado es del tipo "función que toma un entero y devuelve un entero". cuadrado x = x * x

TIPOS PREDEFINIDOS DE DATOS BÁSICOS

Deben escribirse con mayúsculas

TIPOS PREDEFINIDO DE DATOS COMPUESTOS

Sus valores se construyen utilizando otros tipos, por ejemplo: funciones, listas y tuplas.

FUNCIONES Si a y b son dos tipos, entonces a->b es el tipo de una función que toma como argumento un elemento de tipo a y devuelve un valor de tipo b.
Las funciones en Haskell son objetos de primera clase, que pueden ser argumentos o resultados de otras funciones o ser componentes de estructuras de datos.
En Haskell, la función suma tiene el tipo:

DEFINICIÓN DE FUNCIONES

Además de las funciones que ya están en el preludio, podemos definir nuevas funciones, con el siguiente pro- cedimiento:Además de las funciones que ya están en el preludio, podemos definir nuevas funciones, con el siguiente pro- cedimiento:
  1. En Haskell, usamos el comando ‘:edit’,  seguido por el nombre
    de un fichero:  Prelude> :edit nuevo; se activa el editor de
    texto que ocupa temporalmente el lugarde Haskell y en el
    escribimos la definición de la nueva función.
    Por ejemplo
    factorialDe ::Integer->Integer
    factorialDe n=product[1..n]
    Guardamos como: funcionFactorial.hs y luego cerramos
    el editor
    
  2. Volvemos a Haskell y activamos la nueva función:
    Prelude> load “f:\\funcionFactorial.hs” 
  3. Digitamos fac 4 en:  main> factorialDe 4
    y obtendremos como respuesta 24
    

También los siguientes comandos se envían directamente al interprete.

  • :load fichero(s) Permite conocer las funciones que están definidas en los ficheros especificados.
  • :also fichero(s) permite añadir definiciones de otros ficheros, sin eliminar las definiciones existentes.
  • :edit fichero Crear o modificar un fichero. Sin nombre, edit usa el ultimo fichero recuperado y, después de salir del procesador de textos, se carga otra vez.
  • type expresion Determina el tipo de la expresión dada.
  • :set ±letra Permite aplicar o eliminar algunas opciones. Activa y desactiva número de reducciones y cuanta memoria se ha usado.

LISTAS

Si a es un tipo cualquiera, entonces [a] representa el tipo de listas cuyos elementos son valores de tipo a. Así, todos los elementos de una lista deben ser del mismo tipo.
Las formas de escribir expresiones de listas son:
  • La lista vacía, se representa mediante [].
  • Las listas no vacías pueden ser construidas
    • Enunciando explícitamente sus elementos, por ejemplo, [1,3,10].
    • Agregando un elemento al principio de otra lista utilizando el operador de construcción (:).

Estas notaciones son equivalentes:
[1,3,10] = 1:[3,10] = 1:(3:[10]) = 1:(3:(10:[]))

El operador (:) es asociativo a la derecha, de forma que
1: 3: 10:[] equivale a
(1:(3:(10:[]))), lista cuyo primer elemento es 1, el segundo 3 y el último 10.
El standar prelude incluye un amplio conjunto de funciones de manejo de listas.
Ejemplo: length xs devuelve el número de elementos de xs Prelude>length [1,3,10] 3

CADENAS

Las cadenas son tratadas como listas de caracteres y el tipo String se toma como una abreviación de "[Char]". Pueden ser escritas como secuencias de caracteres encerradas entre comillas dobles.
Todos los códigos de escape utilizados para los caracteres, pueden utilizarse para las cadenas.
Ej.
Prelude>"hola" hola

Puesto que las cadenas son representadas como listas de caracteres, todas las funciones del estándar prelude para listas pueden ser utilizadas también con cadenas:
Ej.
Prelude> length "Hola" 4
Prelude> "Hola, " ++ "amigo" Hola, amigo

TUPLAS

A diferencia de las listas cuyos elementos deben ser del mismo tipo, las tuplas pueden agrupar elementos de diferentes tipos, pero su tamaño es fijo. Así, un registro de personas puede contener nombres (cadenas), si alguien es masculino o no (booleano) y fechas de nacimiento (enteros).

En las tuplas, el orden de los elementos es importante y para cada combinación de tipos se crea un nuevo tipo.
Así, si: t1, t2, ..., tn son tipos y =2, entonces hay un tipo de n-tuplas escrito:
(t1, t2, ..., tn)
cuyos elementos pueden ser escritos también como
(x1, x2, ..., xn) donde cada x1, x2,..., xn
tiene tipos t1,t2, ..., tn respectivamente.
Ejemplos:

  • (1, ’{a}’) :: (Int, Char): Tupla con los elementos 1 (entero) y ’a’ (caracter)
  • ("mono", True, 2) :: ([Char], Bool, Int) Tupla con tres elementos: la cadena "mono", el boolean True y el numero 2;
  • ([1,2], sqrt) :: ([Int], Float->Float) Tupla con dos elementos: la lista de enteros [1,2] y la función del tipo de-float-a-float sqrt;
  • (1, (2,3)) :: (Int, (Int,Int)) : Tupla con dos elementos: el numero 1, y la tupla de los números 2 y 3.
  • (1, [2], 3) :: (Int, [Int], Int)
  • ('a', False) :: (Char, Bool)
  • ((1,2),(3,4)) :: ((Int, Int), (Int, Int))
  • Existe una tupla especial con 0 elementos denominada tipo unidad y se escribe como ().
  • Pareja: Tupla con dos elementos.
  • Terna: Tuplas con tres elementos.
  • No existen tuplas de un elemento: la expresión de un entero se puede escribir entre paréntesis

Ejemplos para definir funciones sobre tuplas: mediante análisis por patrones.
fst :: (a,b) -> a
fst (x,y) = x
snd :: (a,b) -> b
snd (x,y) = y
fst3 :: (a,b,c) -> a
fst3 (x,y,z) = x
snd3 :: (a,b,c) -> b
snd3 (x,y,z) = y
thd3 :: (a,b,c) -> c
thd3 (x,y,z) = z

Estas funciones son polimorficas, pero por supuesto también es posible escribir funciones que operen solamente con un tipo de tupla determinado:
f :: (Int,Char) -> [Char]
f (n,c) = intString n ++ [c]

Para agrupar dos elementos del mismo tipo, se puede usar una lista. Pero, en algunos casos, una tupla es más útil. Un punto en dos dimensiones se describe por dos números de tipo Float.

Tal punto puede ser descrito por una lista o por una pareja. En los dos casos es posible definir funciones que hagan algo con puntos. Por ejemplo, una función que calcule la distancia hasta el origen.
La función distanciaL es la versión que usa una lista, distanciaT es la versión para una tupla:
distanciaL :: [Float] -> Float
distanciaL [x,y] = sqrt (x*x+y*y)
distanciaT :: (Float,Float) -> Float
distanciaT (x,y) = sqrt (x*x+y*y)

Mientras se llame la función correctamente, no existe diferencia. Sin embargo, podría suceder que se llamase a la función (por error al teclear, o error lógico) en algún lugar en el programa con tres coordenadas.

Con el uso de distanciaT, el intérprete da un aviso durante el análisis de las funciones: una tupla con tres elementos es diferente de una tupla con dos elementos.
En el caso de distanciaL el intérprete no dice nada: el programa no tiene conflictos de tipos.

Pero cuando se usa el programa, resulta que la función distanciaL no esta definida para listas con tres elementos.
El uso de tuplas en vez de listas es entonces útil para detectar errores lo antes posible.
Otro caso en que las tuplas son realmente útiles es cuando se necesitan funciones con más de un resultado.
Las funciones de varios parámetros son posibles gracias al mecanismo de currificacion; las funciones que tienen varios resultados solamente son posibles agrupando los resultados en una tupla. La tupla en total es entonces un resultado.

Un ejemplo de una función que en realidad tiene dos resultados, es la función splitAt que esta definida en el preludio. Esta función devuelve los resultados de take y drop de una vez.
Por tanto, se puede definir la función de la siguiente forma:
splitAt :: Int -> [a] -> ([a],[a]) splitAt n xs = (take n xs, drop n xs)

El trabajo de estas dos funciones se puede hacer de una vez, por eso se ha definido realmente la función splitAt de forma mas eficiente:

splitAt :: Int -> [a] -> ([a], [a])
splitAt 0 xs = ([] , xs)
splitAt n [] = ([] , [])
splitAt (n+1) (x:xs) = (x:ys, zs)
where (ys,zs) = splitAt n xs

La llamada splitAt 2 "gofer" devuelve la pareja ("go","fer") como resultado. En la definición se puede ver (con una llamada recursiva) como se puede usar una tupla resultante: utilizando patrones (en el ejemplo (ys,zs)).

DEFINICIONES DE TIPOS

Cuando se usan mucho las listas y tuplas, las declaraciones de tipos llegan a ser bastante complicadas.
Por ejemplo, con las funciones sobre puntos como la función distancia .
Las funciones mas simples son entendibles:
distancia :: (Float,Float) -> Float
diferencia :: (Float,Float) -> (Float,Float) -> Float

Sin embargo, es mías complicado con listas sobre puntos, y con funciones de orden superior:
sup_poligono :: [(Float,Float)] -> Float
transf_poligono :: ((Float,Float)->(Float,Float))-> [(Float,Float)] -> [(Float,Float)]

Una definición de tipo es muy útil en estos casos. Con una definición de tipo es posible dar un nombre (mías claro) a un tipo, por ejemplo:
type Punto = (Float,Float)

Con esta definición se pueden escribir las declaraciones de tipo de forma más clara:
distancia :: Punto -> Float
diferencia :: Punto -> Punt -> Float
sup_poligono :: [Punto] -> Float
transf_poligono :: (Punto->Punto) -> [Punto] -> [Punto]

Mejor todavía sería hacer una definición de tipo para ‘polígono’:
type Polígono = [Punto]
sup_poligono :: Polígono -> Float
transf_poligono :: (Punto->Punto) -> Polígono -> Polígono

Con definiciones de tipo hay que tener presentes algunos puntos:

  • La palabra type es una palabra reservada especialmente para estas definiciones de tipo;
  • El nombre de un tipo debe empezar por una letra mayúscula (es una constante, no es una variable);
  • Una declaración de un tipo especifica el tipo de una función; una definición de tipo define un nuevo nombre para un tipo. El intérprete usa el nombre definido simplemente como una abreviatura. Si se pide el tipo de una expresión al intérprete, este muestra (Float,Float) en vez de Punto.

Si se dan dos diferentes nombres a un tipo, por ejemplo en:
type Punto = (Float,Float)
type Complejo = (Float,Float)

Entonces se pueden usar los dos nombres indistintamente.
Un Punto es lo mismo que un Complejo y este es lo mismo que un (Float,Float)

UNIÓN DE TIPOS

Todos los elementos de una lista deben ser del mismo tipo. En una tupla se pueden representar valores de diferentes tipos, pero en las tuplas no es variable el número de elementos. Algunas veces se quiere hacer una lista que tenga elementos del tipo entero y del tipo caracter.

Con una definición de datos se puede construir un tipo IntOrChar que tenga como elementos enteros y caracteres:
data IntOrChar = Ent Int
| Car Char

Con esto se puede hacer una lista mezclada:
xs :: [IntOrChar]
xs = [ Ent 1, Car ’a’, Ent 2, Ent 3 ]

El único precio es que se tiene que marcar cada elemento con una función constructora Ent o Car.
Estas funciones se pueden interpretar como funciones de conversión;
Ent :: Int -> IntOrChar
Car :: Char -> IntOrChar

cuyo uso se puede comparar con el uso de las funciones primitivas
round :: Float -> Int
chr :: Int -> Char

TIPOS ABSTRACTOS

Si se definen dos tipos del mismo modo, por ejemplo:
type Fecha = (Int,Int)
type Ratio = (Int,Int)

Entonces se pueden usar los dos para la misma cosa.
Se pueden usar ‘fechas’ como ‘n´umeros racionales’, sin que el comprobador de tipos (en inglés, type-checker) devuelva errores.

Con las definiciones de datos realmente se pueden hacer nuevos tipos, de modo que no se pueda intercambiar un Ratio con cualquier otro tipo (Int,Int). En vez de la definición de tipos podemos escribir la siguiente definición de datos:
data Ratio = Rat (Int,Int)

Existe entonces solamente una función constructora. Para hacer una fracción con el numerador 3 y el denominador 5, no es suficiente escribir (3,5), sino se tiene que escribir Rat (3,5). Como tipos de unión se puede interpretar a la función Rat como función de conversión de (Int,Int) a Ratio.

Este método se usa mucho para hacer tipos abstractos. Un tipo abstracto consiste en una definición de datos y una serie de funciones que se pueden aplicar al tipo definido (en el caso de Ratio por ejemplo:
qSum, qRes, qMul en qDiv).

Como nombre de una función constructora, muchas veces se elige el mismo nombre que el tipo. Por
ejemplo:
data Ratio = Ratio (Int,Int)

CONCEPTO DE INDUCCIÓN Y RECURSIVIDAD

En la definición de una función se pueden usar las funciones estándar y las funciones definidas por el usuario, pero también se puede usar la propia función que se define en su definición. A tal definición se la llama definición recursiva, como: f x = f x
Las funciones recursivas tienen sentido bajo las siguientes dos condiciones
  • El parámetro de la llamada recursiva es mas simple que el parámetro de la función que se quiere definir 0:55 07/04/2005(por ej., numéricamente menor o una lista mas corta);
  • Existe una definición no recursiva para un caso base.

Una definición recursiva de la función factorial es:
fac n | n==0 = 1
| n>0 = n * fac (n-1)

Donde
  • El caso base es n==0; se puede calcular el resultado directamente (sin recursión).
  • En el caso n>0 existe una llamada recursiva, es decir fac (n-1).
  • El parámetro de esta llamada (n-1) es menor que n.

Otra manera de distinguir estos dos casos (caso base y caso recursivo) es usando patrones:
fac 0 = 1
fac (n+1) = (n+1) * fac n

El parámetro de la llamada recursiva (n) es menor que el parámetro de la función que se quiere definir (n+1).
El uso de patrones tiene mucha relación con la tradición matemática del usar inducción.

Así, la definición matemática de la función potencia puede ser usada casi directamente como

x ^ 0 = 1
x ^ (n+1) = x * x^n

La definición recursiva que usa patrones para distinguir diferentes casos, en lugar de expresiones booleanas, se llama también definición inductiva.

Las funciones sobre listas también pueden ser recursivas. Una lista es ‘menor’ que otra si tiene menos elementos. Así, función suma, puede ser definida de diferentes maneras.

  • Definición recursiva con expresiones booleanas es:
    suma lista | lista==[] = 0 (Sume la lista; si la lista esta vacía de por resultado igual a cero)
    | otherwise = head lista + suma (tail lista) (sino sume la cabeza de lista más la suma de cola)
  • Version inductiva (usando patrones):
    suma [] = 0
    suma (cabeza:cola) = cabeza + suma cola

    Es mas clara una definición con patrones, porque las diferentes partes en el patrón pueden conseguir un nombre directamente, como cabeza y cola en la función suma, cuya versión recursiva requiere funciones estándar head y tail para distinguir las diferentes partes en lista

PATRONES

Comparación de Patrones:
Un patrón es una expresión como argumentoen una ecuación.
Es posible definir una función dando más deuna ecuación paraésta.
Al aplicar la función a un parámetro concretola comparación de patrones determina la ecuación a utilizar.

Regla para la comparación de patrones

  • Se comprueban los patrones correspondientes a las distintasecuaciones en el orden dado por el programa, hasta que seencuentreuna que unifique.
  • Dentro de una misma ecuación se intentanunificarlos patrones correspondientes a losargumentos de izquierda a derecha.
  • En cuanto un patrón falla para un argumento, se pasa a lasiguiente ecuación.

Patrones constantes
Un patrón constante puede ser un número, uncaráctero un constructor de dato.
f :: Integer →Bool
f 1 =True
f 2 =False

La definición de la conjunción y disyunción devalores lógicosusa patrones constantes (TrueyFalseson dos constructores de datos para el tipoBool)

Patrones para listas
Es posible utilizar patrones al definirfuncionesque trabajen con listas.
[ ] sólo unificacon un argumento que sea unalista vacía.
[x ], [x ,y], etc. sólo unifican con listas de uno,dos, etc. argumentos.

(x :xs) unificacon listas con al menos un elemento
suma :: [Integer] →Integer
suma [ ] = 0
suma (x :xs) = x + suma xs

Patrones para tuplas
primero2 :: (Integer,Integer) →Integer
primero2 (x ,y) = x
primero3 :: (Integer,Integer,Integer) →Integer
primero3 (x ,y,z ) = x

Los patrones pueden anidarse.
sumaPares:: [(Integer,Integer)] →Integer
sumaPares[ ] = 0
sumaPares((x ,y) :xs) = x + y +sumaPares xs

Patrones aritméticos
Es unpatrón de la forma (n + k), donde k esun valor constante natural.
factorial :: Integer →Integer
factorial 0 = 1
factorial (n + 1) = (n + 1) *factorial n

DEFINICIÓN POR ANÁLISIS DE PATRONES

Se llaman parámetros formales a los parámetros de una función en la definición de la misma, por ejemplo x e y en: f x y = x * y

En una llamada a la función se dan parámetros actuales a la función, así en: f 17 (1+g 6)

  • El parámetro actual es 17 que corresponde a x.
  • El parámetro actual es (1+g 6) que corresponde a y.

Los parámetros actuales se sustituyen en los lugares de los parámetros formales cuando se llama a una función.
El resultado del anterior ejemplo es por tanto 17*(1+g 6). Por tanto, los parámetros actuales son expresiones. Los parámetros formales eran hasta ahora solamente nombres

ENCAJE DE PATRONES SIMPLE

La declaración de una función f está formada por un conjunto de ecuaciones con el formato:
f < pat1 > < pat2 > . . . < patn > = < expresion >

Si f fuese un operador sería
f < pat2 > = < expresion >

Donde cada una de las expresiones < pat1 > < pat2 > . . .
representa un argumento de la función y se denominado un patrón.
El número n de argumentos se denomina paridad.

Cuando una función está definida mediante más de una ecuación, será necesario evaluar una o más argumentos de la función para determinar cuál de las ecuaciones aplicar. Este proceso se denomina encaje de patrones. En los ejemplos anteriores se utilizó el patrón más simple: una variable. Así, en la definición de factorial: fact n = product [1..n], si se desea evaluar la expresión "fact 6" es necesario:

  • Encajar la expresión "6" con el patrón "n" y
  • Luego evaluar la expresión obtenida a partir de "product [1..n]" substituyendo la "n" con el "6".

OTROS TIPOS DE PATRONES:
ANÓNIMOS: Se representan por el caracter (_) y encajan con cualquier valor, pero no es posible referirse posteriormente a dicho valor.
Ejemplo:
cabeza (x:_) = x
cola (_:xs) = xs

PATRONES CON NOMBRE:
Para poder referirnos al valor que está encajando, por ejemplo, en lugar de definir f como:
f (x:xs) = x:x:xs

Podría darse un nombre a x:xs mediante un patrón con nombre:
f p@(x:xs) = x:p

PATRONES n+k:
Encajan con un valor entero mayor o igual que k. El valor referido por la variable n es el valor encajado menos k. Ejemplo:
x ^ 0 = 1
x ^ (n+1) = x * (x ^ n)

FUNCIONES DE ORDEN SUPERIOR SOBRE LISTAS

Las funciones pueden ser más flexibles utilizando funciones como parámetros. Muchas funciones sobre listas tienen una función como parámetro. A estas se les llama funciones de orden superior.
  • map: Función de orden superior basada en el principio general ‘recorrer todos los elementos de una lista’. La función parámetro de map se aplica a cada elemento de la lista. La función map aplica su parámetro función a todos los elementos de una lista. Ejemplos:
    xs = [ 1 , 2 , 3 , 4 , 5 ]
    map cuadrado xs = [ 1 , 4 , 9 , 16 , 25 ]
    Prelude>map (1+) [1..10]
    [2,3,4,5,6,7,8,9,10,11]
  • filter (filtro).
    Función devuelve los elementos de una lista que cumplen alguna condición que se da a la función filter en forma de una función booleana.
    xs = [ 1 , 2 , 3 , 4 , 5 ]
    filter event xs = [ 2 , 4 , ]
    Prelude>filter even [1..10]
    [4, 6, 8, 10]
  • foldr:
    Pliega la lista a un valor colocando un operador (uno de los dos parámetros), entre los elementos de la lista. La función empieza por la derecha con el valor inicial (el otro parámetro).
    Existe también una función foldl, que empieza por la izquierda.
    La función foldr inserta un operador entre todos los elementos de una lista, empezando a la derecha con un valor dado:
    xs = [ 1 , 2 , 3 , 4 , 5 ]
    foldr (+) 0 xs = [ 1+( 2+ (3+ (4+ (5+0)))) ]

Mónadas
  • El grupo de las operaciones de entrada salida en Haskell se denota como IO ().
    Una exprosion de tipo IO () denota una acción; cuando se evalúa, la acción se realiza.
  • Escribir un carácter:
    putChar :: Char → IO ()
  • No hacer nada
    done :: IO ()
  • Combinar dos acciones de E/S
    (>>) :: IO () → IO () → IO ()
  • Escribir un String
    write :: String → IO ()
    write [] = done
    write (x:xs) = putChar x >> write xs
  • Escribir un String terminado en retorno de carro
    writeln :: String → IO ()
    writeln xs = write xs >> putchar '\n'
  • Leer un carácter
  • getChar :: IO Char
  • Generalización de done
    return :: a → IO a
  • Implementaci on de done
    done :: IO ()
    done = return ()
  • Generalización del tipo de (>>)
    (>>) :: IO a → IO b → IO b
    si p y q son acciones, entonces p >> q es una acción que, cuando se realice, primero efectúa p, ignora el valor devuelto y despus realiza q.
  • Generalización de (>>)
    (>>=) :: = IO a → (a → IO b) → IO b
  • Leer n caracteres
    readn :: Iont → IO String
    readn 0 = return []
    readn n = getChar >>= q
    where q c = read (n-1) >>= r
    where r cs = return (c:cs)
  • Clase Monad
    class Monad m where
    return :: a → m a
    (>>=) :: m a → (a → m b) → m b
  • Notación do
    readn :: Iont → IO String
    readn 0 = return []
    readn n = c ← getChar
    cs ← readn (n-1)
    return (c:cs)

Leyes de las Mónadas
  • return es un elemento neutro por la derecha de >> p >>= return == p
  • return es un elemento neutro por la izquierda de >> en el sentido (return e) >>= q = q e
  • >>= es asociativa en el siguiente sentido (p >>= q) >>= r = p >>= s where s x = (q x >>= r)

PARADIGMA
La ignorancia niega o agrede o critica
La ciencia duda..!!
Wilucha

PARADIGMAS IMPRESOS:
Lenguajes Gramáticas Autómatas Series
Laplace Ecuación Operador Compilador

PARADIGMA
Cultivo una rosa blanca
..en julio, como en enero
para el amigo sincero
que me da su mano franca..!!

Y para el cruel que me arranca
el corazón con que vivo,
cardo ni ortiga cultivo;
..cultivo una rosa blanca..!
José Martí

Mis Paradigmas

Te espero en: wilucha@gmail.com

Esta page está en: www.wilocarpio.com.ar

11/09/2002

Volver al principio