ANTOLOGA DE
PROGRAMACIN
LGICA Y FUNCIONAL
CONTENIDO
UNIDAD 1.Conceptos Fundamentales .............................. 6
1.1. Estilos de programacin ........................................................................... 8
1.2. Evaluacin de expresiones. .................................................................... 12
1.3. Definicin de funciones. ......................................................................... 15
1.4. Disciplina de tipos. .................................................................................. 17
1.5. Tipos de datos ......................................................................................... 18
UNIDAD 2. Programacin Funcional .............................. 22
2.1. El tipo de datos ........................................................................................ 24
2.2. Funciones ................................................................................................ 34
2.3. Intervalos ................................................................................................. 35
2.4. Operadores .............................................................................................. 36
2.5. Aplicaciones de las listas ....................................................................... 37
2.6. rboles ..................................................................................................... 40
UNIDAD 3. Evaluacin perezosa.................................. 42
3.1. Estrategias de evaluacin perezosa....................................................... 44
3.2. Tcnicas de programacin funcional perezosa..................................... 47
UNIDAD 4. Fundamentos de la programacin lgica.................. 50
4.1. Repaso de lgica de primer orden ......................................................... 52
4.2. Unificacin y Resolucin ........................................................................ 55
4.3. Clusulas de Horn. Resolucin SLD ...................................................... 56
4.4. Programacin lgica con clusulas de Horn ......................................... 62
4.5. Consulta de una base de clusulas ....................................................... 63
4.6. Representacin causada del conocimiento........................................... 63
4.7. Consulta de una base de clusulas ....................................................... 70
4.8. Espacios de bsqueda ............................................................................ 70
4.9. Programacin lgica con nmeros, listas y rboles. ............................ 74
BIBLIOGRAFIA ............................................... 91
Conceptos Fundamentales
Programacin Funcional
Programacin Lgica y
Funcional
Evaluacin Perezosa
Estilos de Programacin
Evaluacin de Expresiones
Conceptos
fundamentales
Definicin de funciones
Disciplina de Tipos
Tipo de Datos
Estilo de identacin
Estilo de indentacin, en lenguajes de programacin que usan llaves para identar
o delimitar bloques lgicos de cdigo, como por ejemplo C, es tambin un punto
clave el buen estilo. Usando un estilo lgico y consistente hace el cdigo de uno
ms legible. Comprese:
if(horas < 24 && minutos < 60 && segundos < 60){
return true;
}else{
return false;
}
o bien:
return horas < 12 && minutos < 60 && segundos < 60;
La diferencia es, con frecuencia, puramente estilstica y sintctica, ya que los
compiladores modernos producirn cdigo objeto idntico en las dos formas.
Bucles y estructuras de control
El uso de estructuras de control lgicas para bucles tambin es parte de un buen
estilo de programacin. Ayuda a alguien que est leyendo el cdigo a entender la
secuencia de ejecucin (en programacin imperativa). Por ejemplo, el siguiente
pseudocdigo:
cuenta = 0
while cuenta < 5
print cuenta * 2
cuenta = cuenta + 1
endwhile
El extracto anterior cumple con las dos recomendaciones de estilo anteriores, pero
el siguiente uso de la construccin for hace el cdigo mucho ms fcil de leer:
Espaciado
Los lenguajes de formato libre ignoran frecuentemente los espacios en blanco. El
buen uso del espaciado en la disposicin del cdigo de uno es, por tanto,
considerado un buen estilo de programacin.
Comprese el siguiente extracto de cdigo C:
int cuenta;
for(cuenta=0;cuenta<10;cuenta++){printf("%d",cuenta*cuenta+cu
enta);}
con:
int cuenta;
for (cuenta = 0; cuenta < 10; cuenta++)
{
printf("%d", cuenta * cuenta + cuenta);
}
En los lenguajes de programacin de la familia C se recomienda tambin evitar el
uso de caracteres tabulador en medio de una lnea, ya que diferentes editores de
textos muestran su anchura de forma diferente.
Ternarios: 3 operandos.
El orden en que se evalan los operandos viene dado por unas reglas:
Reglas de procedencia
Reglas de asociatividad
Uso de parntesis
EVALUACIN DE EXPRESIONES
Toda expresin regresa un valor. Si hay ms de un operador, se evalan primero operadores
mayor precedencia, en caso de empate, se aplica regla asociatividad
Para evaluar una expresin no hay que hacer nada del otro mundo, pues es bien sencillo.
Slo hay que saber sumar, restar, si un nmero es mayor que otro
Hay tres reglas de prioridad a seguir para evaluar una expresin:
Las expresiones son secuencias de constantes y/o variables separadas por operadores
vlidos.
Se puede construir una expresin vlida por medio de :
1. Una sola constante o variable, la cual puede estar precedida por un signo + .
2. Una secuencia de trminos (constantes, variables, funciones) separados por operadores.
Adems debe considerarse que:
Toda variable utilizada en una expresin debe tener un valor almacenado para que la
expresin, al ser evaluada, d como resultado un valor.
Cualquier constante o variable puede ser reemplazada por una llamada a una funcin.
Como en las expresiones matemticas, una expresin en Pascal se evala de acuerdo a la
precedencia de operadores
JERARQUA DE OPERADORES
El orden general de evaluacin de los operadores de una expresin va de izquierda a
derecha, con la excepcin de las asignaciones que lo hacen de derecha a izquierda.
Podemos seguir las siguientes tres reglas de evaluacin de expresiones:
(Regla 1) En todas las expresiones se evalan primero las expresiones de los parntesis ms
anidados (interiores unos a otros); y stos modifican la prioridad segn la cantidad de stos,
los cuales tienen que estar balanceados (el mismo nmero de parntesis que abren debe ser
igual al nmero de los parntesis que cierran).
Pascal
Cercano a tener disciplina de tipos pero no realiza comprobacin de tipos en los registros
variantes (incluso puede omitirse la etiqueta discriminatoria en dichos registros)
Ada
Java
ML y Haskell
Los tipos de los parmetros de las funciones (y de estas mismas) se conocen en tiempo de
compilacin (ya sea por declaracin del usuario o por inferencia de tipos)
Haskell y otros lenguajes funcionales utilizan el sistema de tipos de Milner, que tiene dos
caractersticas fundamentales:
Todos los datos tienen un tipo asociado con ellos. Un dato puede ser un simple carcter, tal
como `b, un valor entero tal como 35. El tipo de dato determina la naturaleza del conjunto
de valores que puede tomar una variable.
Numricos
Simples Lgicos
Alfanumricos (string)
Tipos de datos Arreglos (Vectores, Matrices)
Estructurados Registros (Def. por el Archivos usuario) Apuntadores
Int
Integer
Char
Bool
Lgicamente podemos construir listas, tuplas y funciones con esos tipos de datos. Otro tipo
que tenemos presente en Haskell es el tipo polimrfico. As podemos construir estructuras y
funciones polimrficas.
Dentro de las caractersticas de los tipos de Haskell podemos deducir que cada expresin
tiene un nico tipo principal y que ese tipo principal se puede deducir automticamente.
Adems, Haskell incorpora las funciones sobrecargadas que se pueden aplicar sobre varios
tipos pero no sobre todos los tipos. Para ello se dispone de una jerarqua de clases de tipos
con operadores y funciones sobrecargadas como:
RESUMEN
El manejo de estndares y recomendaciones de programacin facilitaran al
programador la documentacin y seguimiento de sus proyectos an con el paso
del tiempo.
Mejorar el mantenimiento del software y permitir que el cdigo pueda ser ledo
por cualquier persona de la empresa que conozca los estndares de codificacin.
Es necesario indicar que las recomendaciones son exactamente mejores
El tipo de datos
Funciones
Intervalos
Programacin
Funcional
Operadores
rboles
::
::
::
::
::
Integer
Char
Integer -> Integer
[Integer]
(Char,Integer)
= n+1
e1 => e2
Por ejemplo:
inc (inc 3)
=> 5
2.1.
Tipos Polimrficos
Haskell proporciona tipos polimficos ---tipos que son cuantificados universalmente sobre
todos los tipos. Tales tipos describen esencialmente familias de tipos. Por ejemplo,
(para_todo a)[a] es la familia de las listas de tipo base a, para cualquier tipo a. Las listas
de enteros (e.g. [1,2,3]), de caracteres (['a','b','c']), e incluso las listas de listas de
interos, etc., son miembros de esta familia. (Ntese que [2,'b'] no es un ejemplo vlido,
puesto que no existe un tipo que contenga tanto a 2 como a 'b'.)
[Los identificadores tales como el anterior a se llaman variables de tipo, y se escriben en
minscula para distinguirlas de tipos especficos, como Integer. Adems, ya que Haskell
Esta definicin es auto-explicativa. Podemos leer las ecuaciones como sigue: "La longitud
de la lista vaca es 0, y la longitud de una lista cuyo primer elemento es x y su resto es xs
viene dada por 1 ms la longitud de xs." (Ntese el convenio en el nombrado: xs es el
plural de x, y x:xs debe leerse: "una x seguida de varias x).
Este ejemplo, adems de intuitivo, enfatiza un aspecto importante de Haskell que debemos
aclarar: la comparacin de patrones (pattern matching). Los miembros izquierdos de las
ecuaciones contienen patrones tales como [] y x:xs. En una aplicacin o llamada a la
funcin, estos patrones son comparados con los argumentos de la llamada de forma
intuitiva ([] solo "concuerda" (matches) o puede emparejarse con la lista vacia, y x:xs se
podr emparejar con una lista de al menos un elemento, instancindose x a este primer
elemento y xs al resto de la lista). Si la comparacin tiene xito, el miembro izquierdo es
evaluado y devuelto como resultado de la aplicacin. Si falla, se intenta la siguiente
ecuacin, y si todas fallan, el resultado es un error.
La definicin de funciones a travs de comparacin de patrones es usual en Haskell, y el
usuario deber familiarizarse con los distintos tipos de patrones que se permiten;
volveremos a esta cuestin en la Seccin 4.
La funcin length es tambin un ejemplo de funcin polimrfica. Puede aplicarse a listas
con elementos de cualquier tipo, por ejemplo [Integer], [Char], o [[Integer]].
=> 3
length ['a','b','c'] => 3
length [[1],[2],[3]] => 3
length [1,2,3]
He aqu dos funciones polimrficas muy tiles sobre listas, que usaremos ms tarde. La
funcin head devuelve el primer elemento de una lista, y la funcin tail devuelve la lista
salvo el primero:
head
head (x:xs)
:: [a] -> a
= x
tail
tail (x:xs)
Al contrario que length, estas funciones no estan definidas para todos los posibles valores
de su argumento. Cuando las funciones son aplicadas a la lista vaca se produce un error en
tiempo de ejecucin.
Vemos que algunos tipos polimrficos son ms generales que otros en el sentido de que el
conjunto de valores que definen es ms grande. Por ejemplo, el tipo [a] es ms general
que [Char]. En otras palabras: el tipo [Char] puede ser derivado del tipo [a] a travs de
una sustitucin adecuada de a. Con respecto a este orden generalizado, el sistema de tipos
de Haskell tiene dos propiedades importantes: en primer lugar, se garantiza que toda
expresin bien tipificada tenga un nico tipo principal (descrito despus), y en segundo
lugar, el tipo principal puede ser inferido automticamente (4.1.4). En comparacin con un
lenguaje con tipos monomrficos como C, el lector encontrar que el polimrfismo
enriquece la expresividad, y que la inferencia de tipos reduce la cantidad de tipos usados
por el programador.
El tipo principal de una expresin o funcin es el tipo ms general que, intuitivamente,
"contiene todos los ejemplares de la expresin." Por ejemplo, el tipo principal de head es
[a]->a; los tipos [b]->a, a->a, o el propio a son demasiado generales, mientras que algo
como [Integer]->Integer es demasiado concreto. La existencia de un nico tipo
principal es la caracterstica esencial del sistema de tipos de Hindley-Milner, que es la base
del sistema de tipos de Haskell, ML, Miranda, ("Miranda" es marca registrada de Research
Software, Ltd.) y otros lenguajes (principalmente funcionales) .
2.2.
Podemos definir nuestros propios tipos en Haskell a travs de una declaracin data, que
introduciremos con una serie de ejemplos (4.2.1).
Un dato predefinido importante en Haskell corresponde a los valores de verdad:
data Bool
= False | True
El tipo definido con tal declaracin es Bool, y tiene exactamente dos valores: True y
False. Bool es un ejemplo de constructor de tipo (sin argumentos), mientras que True y
False son constructores de datos (o constructores, para abreviar).
Tanto Bool como Color son ejemplos de tipos enumerados, puesto que constan de un
nmero finito de constructores.
El siguiente es un ejemplo de tipo con un solo constructor de dato:
data Point a
= Pt a a
Al tener un solo constructor, un tipo como Point es llamado a menudo un tipo tupla, ya
que esencialmente es un producto cartesiano (en este caso binario) de otros tipos. (La tuplas
son conocidas en otros lenguajes como registros.) Por el contrario, un tipo multiconstructor, tal como Bool o Color, se llama una "suma de tipos" o tipo unin (disjunta).
Sin embargo, lo ms importante es que Point es un ejemplo de tipo polimrfico: para
cualquier tipo t, define el tipo de los puntos cartesianos que usan t como eje de
coordenadas. El tipo Point puede tambin verse como un constructor de tipos unario, ya
que a partir de un tipo t podemos obtener un nuevo tipo Point t. (En el mismo sentido,
usando el ejemplo de la listas, [] es tambin un constructor de tipos: podemos aplicar el
constructor [] a un tipo t para obtener un nuevo tipo [t]. La sintaxis de Haskell permite
escribir [t] en lugar de [] t. Similarmente, -> es otro constructor de tipos binario: dados
dos tipos "t" y "u", t->u es el tipo de las funciones que aplican datos de tipo "t" a elementos
de tipo "u".)
Ntese que el tipo del constructor de datos Pt es a -> a -> Point a, y las siguientes
asignaciones de tipos son vlidas:
Pt 2.0 3.0
Pt 'a' 'b'
Pt True False
:: Point Float
:: Point Char
:: Point Bool
Por otro lado, una expresin tal como Pt 'a' 1 est errneamente tipificada, ya que 'a' y
1 son de tipos diferentes.
Es importante distinguir entre la aplicacin de un constructor de datos para obtener un
valor, y la aplicacin de un constructor de tipos para obtener un tipo; el primero tiene lugar
durante el tiempo de ejecucin, que es cuando se computan cosas en Haskell, mientras que
el ltimo tiene lugar en tiempo de compilacin y forma parte del proceso de tipificado que
asegura un "tipo seguro".
[Constructores de tipo como Point y constructores de datos como Pt aparecen en niveles
distintos de la declaracin, lo que permite que el mismo nombre pueda usarse como
constructor de tipos y como constructor de datos, como vemos en:
data Point a = Point a a
Esto puede llevar a una pequea confusin al principio, pero sirve para crear un enlace
obvio entre el constructor de datos y el de tipo.]
2.2.1.
Tipos recursivos
Los tipos pueden ser recursivos, como el siguiente tipo para rboles binarios:
data Tree a
Con ello hemos definido un tipo polimrfico cuyos elementos son o bien hojas conteniendo
un valor de tipo a, o nodos internos ("ramas") conteniendo (en forma recursiva) dos
subrboles.
En la lectura de declaraciones de datos como la anterior, recordemos que Tree es un
constructor de tipos, mientras que Branch y Leaf son constructores de datos. La
declaracin anterior, adems de establecer una conexin entre estos constructores, define
esencialmente los tipos para los constructores Branch y Leaf:
Branch
Leaf
Con este ejemplo tenemos un tipo suficientemente rico que permite definir algunas
funciones (recursivas) interesantes que hagan uso de ste. Por ejemplo, supongamos que
queremos definir una funcin fringe que devuelva todos los elementos de las hojas de un
rbol de izquierda a derecha. En primer lugar es esencial escribir el tipo de la nueva
funcin; en este caso vemos que el tipo debe ser Tree a -> [a]. Es decir, fringe es una
funcin polimrfica que, para cualquier tipo a, aplica rboles de a sobre listas de a. Una
definicin adecuada es la siguiente:
fringe
:: Tree a -> [a]
fringe (Leaf x)
= [x]
fringe (Branch left right) = fringe left ++ fringe right
donde ++ es el operador infijo que concatena dos listas (su definicin completa se ver en la
Section 9.1). Al igual que la funcin length vista anteriormente, la funcin fringe est
definida mediante comparacin de patrones, salvo que los patrones implicados son los
constructores de la definicin dada por el usuario: Leaf y Branch. [Ntese que los
parmetros formales son fcilmente identificados ya que comienzan con letras minsculas.]
2.3.
Sinnimos de Tipos
Por conveniencia, Haskell proporciona una forma para definir sinnimos de tipos; es decir,
nombres de tipos usados varias veces. Los sinnimos de tipo son creados a travs de una
declaracin type (4.2.2). He aqu algunos ejemplos:
type
type
type
data
String
Person
Name
Address
=
=
=
=
[Char]
(Name,Address)
String
None | Addr String
Los sinnimos no definen tipos nuevos, sino simplemente proporcionan nuevos nombres a
tipos ya existentes. Por ejemplo, el tipo Person -> Name es precisamente equivalente al
tipo (String,Address) -> String. Los nombres nuevos son a menudo ms cortos que
los tipos nombrados, pero ste no es el nico propsito de los sinnimos de tipos: stos
pueden mejorar la legibilidad de los programas a travs de nemotcnicos; en efecto, los
ejemplos anteriores enfatizan este hecho. Podemos dar nuevos nombres a tipos
polimrficos:
type AssocList a b
= [(a,b)]
Este es el tipo de las "listas de asociaciones" que asocian valores de tipo a con otros de tipo
b.
2.4.
Antes hemos introducido varios tipos "predefinidos" tales como listas, tuplas, enteros y
caracteres. Tambin mostramos como el programador puede definir nuevos tipos. Adems
de una sintaxis especial los tipos predefinidos tienen algo ms de especial? La respuesta es
no. La sintaxis especial es por conveniencia y consistencia, junto a algunas razones
histricas, pero no tiene ninguna consecuencia semntica.
Enfatizamos este punto diciendo que la apariencia de las declaraciones de stos tipos
predefinidos es especial. Por ejemplo, el tipo Char puede ser descrito en la forma:
data Char
Haskell
-- Esto no es cdigo
-- vlido!
Los nombres de los constructores no son vlidos sintcticamente; ello lo podramos arreglar
escribiendo algo como lo siguiente:
data Char
= Ca | Cb | Cc | ...
| CA | CB | CC | ...
| C1 | C2 | C3 | ...
...
Tales constructores son ms concisos, pero no son los habituales para representar
caracteres.
En cualquier caso, la escritura de cdigo "pseudo-Haskell" tal como la anterior ayuda a
aclarar la sintaxis especial. Vemos que Char es, en efecto, un tipo enumerado compuesto de
un gran nmero de constructores (constantes). Por ejemplo, visto Char de esta forma
aclaramos qu patrones pueden aparecer en las definiciones de funciones; es decir, qu
constructores de este tipo podemos encontrarnos.
Este ejemplo tambin muestra el uso de los comentarios en Haskell; los caracteres -- y los
sucesivos hasta el final de la lnea son ignorados. Haskell tambin permite comentarios
anidados que tienen las forma {-...-} y pueden aparecer en cualquier lugar (2.2).]
Similarmente, podemos definir Int (enteros de precisin limitada) y Integer en la forma:
data Int
= -65532 | ... | -1 | 0 | 1 | ... | 65532
cdigo
data Integer =
... -2 | -1 | 0 | 1 | 2 ...
-- ms pseudo-
donde -65532 y 65532, representan el mayor y el menor entero en precisin fija para una
implementacin concreta. Int es un tipo enumerado ms largo que Char, pero es finito! Por
el contrario, el pseudo-cdigo para Integer (el tipo de los enteros con precisin arbitraria)
debe verse como un tipo enumerado infinito.
Las tuplas tambin son fciles de definir en la misma forma:
data (a,b)
cdigo
data (a,b,c)
data (a,b,c,d)
.
.
.
= (a,b)
-- ms peudo-
= (a,b,c)
= (a,b,c,d)
.
.
.
Cada una de las declaraciones anteriores define una tupla de una longitud particular, donde
(...) juega distintos papeles: a la izquierda como constructor de tipo, y a la derecha como
constructor de dato. Los puntos verticales despus de la ltima declaracin indican un
nmero infinito de tales declaraciones, reflejando el hecho de que en Haskell estn
permitidas las tuplas de cualquier longitud.
La listas son manipulables fcilmente, y lo que es ms importante, son recursivas:
data [a]
cdigo
= [] | a : [a]
-- ms peudo-
Vemos que esto se ajusta a lo ya dicho sobre listas: [] es la lista vaca, y : es el constructor
infijo de listas; de esta forma [1,2,3] es equivalente a la lista 1:2:3:[]. (: es asociativo a
la derecha.) El tipo de [] es [a], y el tipo de : es a->[a]->[a].
[De esta forma ":" est definido con una sintaxis legal---los constructores infijos se
permiten en declaraciones data, y (para describir la comparacin de patrones) son
distinguidos de los operadores infijos ya que comienzan con el carcter ":" (una propiedad
satisfecha trivialmente por ":").]
En este punto, el lector deber notar con cuidado las diferencias entre tuplas y listas, ya que
las definiciones anteriores lo aclaran suficientemente. En particular, ntese la naturaleza
recursiva de las listas, con longitud arbitraria y cuyos elementos son homogneos, y la
naturaleza no recursiva de una tupla concreta, que tiene una longitud fija, en la cual los
elementos son heterogneos. Las reglas de tipificado para tuplas y listas deberan quedar
claras ahora:
Para (e1,e2,...,en), n>=2, si ti es el tipo de ei, entonces el tipo de la tupla es (t1,t2,...,tn).
Para [e1,e2,...,en], n>=0, cada ei debe tener el mismo tipo t, y el tipo de la lista es [t].
2.4.1
Como en algunos dialectos de Lisp, las listas son muy tiles en Haskell, y al igual que en
otros lenguajes funcionales, existe an una sintaxis ms adecuada para su descripcin.
Adems de los constructores de listas ya introducidos, Haskell proporciona expresiones
conocidas como listas por comprensin que introducimos con un ejemplo:
[ f x | x <- xs ]
Intuitivamente, esta expresin puede leerse como "la lista de todos los f x tales que x
recorre xs." La similitud con la notacin de los conjuntos no es una coincidencia. La frase
x <- xs se llama un generador, y pueden utilizarse varios, como en :
[ (x,y) | x <- xs, y <- ys ]
Tal lista por comprensin determina el producto cartesiano de dos listas xs y ys. Los
elementos son seleccionados como si los generadores fueran anidados de izquierda a
derecha (con el de ms a la derecha variando el ltimo); es decir, si xs es [1,2] e ys es
[3,4], el resultado es [(1,3),(1,4),(2,3),(2,4)].
Adems de los generadores, se permiten expresiones booleanas llamadas guardas que
establecen restricciones sobre los elementos generados. Por ejemplo, he aqu una definicin
compacta del algoritmo de ordenacin favorito de todo el mundo:
quicksort []
quicksort (x:xs)
=
=
++
++
[]
quicksort [y | y <- xs, y<x ]
[x]
quicksort [y | y <- xs, y>=x]
Como otra ayuda en la descripcin de listas, Haskell admite una sintaxis especial para
secuencias aritmticas, que mostramos con una serie de ejemplos:
=> [1,2,3,4,5,6,7,8,9,10]
[1,3..10] => [1,3,5,7,9]
[1,3..]
=> [1,3,5,7,9, ... (secuencia infinita)
2.4.2 Cadenas
[1..10]
Como otro ejemplo de sintaxis especial para tipos predefinidos, hacemos notar que la
cadena de caracteres "hello" es una forma simplificada de la lista de caracteress
['h','e','l','l','o']. Adems, el tipo de "hello" es String, donde String es un
sinnimo de tipo predefinido:
type String
= [Char]
Esto significa que podemos usar las funciones polimrficas sobre listas para operar con
cadenas (strings). Por ejemplo:
"hello" ++ " world"
2.2. Funciones
2.3. Intervalos
2.4. Operadores
Here, we have a pair of integers, 5 and 3. In Haskell, the first element of a pairneed
not have the same type as the second element: that is, pairs are allowed to be
heterogeneous heterogeneous. For instance, you can have a pair of an integer with
a string. This contrasts with lists, which must be made up of elements of all the same
type (we will discuss lists further in Section 3.3).
There are two predefined functions that allow you to extract the first and
secondvelements of a pair. They are, respectively, fst and snd. You can see how
they workvbelow:
In addition to pairs, you can define triples, quadruples etc. To define a triple and a
quadruple, respectively, we write:
Exercise 3.2 Use a combination of fst and snd to extract the character out of the
tuple ((1,a),"foo").
Lists
The primary limitation of tuples is that they hold only a fixed number of elements:
pairs hold two, triples hold three, and so on. A data structure that can hold an
arbitrary number of elements is a list. Lists are assembled in a very similar fashion
to tuples, except that they use square brackets instead of parentheses. We can
define a list like:
Lists dont need to have any elements. The empty list is simply []. Unlike tuples, we
can very easily add an element on to the beginning of the list using the colon
operator. The colon is called the cons operator; the process of adding an element
is called consing. The etymology of this is that we are constructing a new list from
an element and an old list. We can see the cons operator in action in the following
examples:
We can actually build any list by using the cons operator (the colon) and the empty
list:
In fact, the [5,1,2,3,4] syntax is syntactic sugar for the expression using the explicit
cons operators and empty list. If we write something using the [5,1,2,3,4] notation,
the compiler simply translates it to the expression using (:) and [ ].
One further difference between lists and tuples is that, while tuples are
heterogeneous, lists must be homogenous. This means that you cannot have a list
that holds both integers and strings. If you try to, a type error will be reported. Of
course, lists dont have to just contain integers or strings; they can also contain tuples
or even other lists. Tuples, similarly, can contain lists and other tuples. Try some of
the following:
There are two basic list functions: head and tail. The head function returns the first
element of a (non-empty) list, and the tail function returns all but the first element of
a (non-empty) list. To get the length of a list, you use the length function:
2.6. rboles
Actividades de Aprendizaje
Identificar los conceptos bsicos de la evaluacin perezosa.
Describir las tcnicas de la programacin funcional perezosa.
Investigar, al menos, una tcnica de programacin funcional perezosa vista en
clase.
Realizar mapa conceptual de la evaluacin perezosa
Aplicar una tcnica de la programacin funcional perezosa, para resolver un
problema real a travs de la modularidad en una situacin sencilla.
BUSQUEDA NO DETERMINISTA
Un algoritmo no determinista
-Ofrece muchos posibles resultados
-Emplean modelos de computacin tales como la maquina de turing probabilstica, que no
son deterministas
-puede simularse utilizando la lista de xitos como por ejemplo x=x, x candidatos, validos
DATOS NO DETERMINISTAS
Requiere tipo de datos diferente como son
Data list m a= nil (cons (m a)(m(list a))
Puede representar lista perezosa no determinista.
Cons [2] [Nil, cons[1]]:: list{} int
Los argumentos de cons representan computacin no determinista, permute y lsSorted se
pueden adaptar a la lista de tipo permute y genera permutaciones perezosamente los
rendimientos isSorted [true, false]es aplicada por encima de la lista (s).
PROGRAMACION FUNCIONAL-LOGICA
La programacin lgica, junto con la funcional, forma parte de los que se conoce como
programacin declarativa. En los lenguajes tradicionales, la programacin consiste en como
RESUMEN
Las diversas tcnicas estudiadas en la unidad nos presentan las tcnicas sobre
programacin de funciones, y sobre su evaluacin.
Mientras se consideren estas recomendaciones se prev la obtencin de un buen
software que cumple su objetivo de forma correcta.
Unificacin y resolucin
Espacios de bsqueda
Programacin lgica con nmeros,
listas y rboles
Control de bsqueda en programas
lgicos
Manipulacin de trminos. Predicados
metalgicos
Actividades de Aprendizaje
L2
L3...
A slightly form of this is a Horn Clause, where the restriction is that only one of the literals
is un-negated. For example:
1.
L1
2.
L1
3. M
4.
L1
L2
L2
L3 ...
L3 ...
are all Horn Clauses. It is straightforward to show that, for example, (2) is equivalent to
L1 L2 L3 ...=> M
or in goal-directed form:
M => L1 L2 L3 ...
This is the typical form of a statement in the logic programming language Prolog. There are
two modes in Prolog. In the consult mode, one supplies the system with axioms. (Note that
the ``'' is replaced by ``:-'', that capitalized symbols are variables, and that the ``.'' is
important.)
grandson(X,Y) :- son(X,Z),parent(Y,Z).
son(charles,elizabeth).
parent(george,elizabeth).
with Prolog telling us that there are no database facts to verify the statement. Or we might
ask
?- grandson(W,george).
Starting with this query, Prolog tries to justify each literal on the RHS by finding a
matching literal in the LHS of another clause in the database. In our example, it would find
dbase statement 1 and perform the unification (W/X, george/Y). So the RHS becomes
son(X,Z),parent(george,Z). It then uses dbase statement 2 to perform the unification
(X/charles, Z/elizabeth), leaving parent(george,elizabeth) to be verified. Obviously, dbase
statement 3 does this with no unification. The system returns the unification for W which is
(W/X/charles), ie charles.
?- grandson(W,george).
W = charles ?
yes
Hemos visto ya un buen nmero de convenciones que debemos utilizar para escribir
programas en Prolog. La ltima parte de este tema la dedicaremos a conocer
detalladamente las reglas sintcticas que hemos de seguir para que nuestras bases de
conocimientos sean reconocidas por Visual Prolog.
Como ya hemos estudiado, un programa Prolog no es ms que la especificacin de una
base de conocimientos lgica con las caractersticas siguientes:
Operador
Operando 2
Resultado
+, -, *
entero
entero
real
+, -, *
entero
real
entero
+, -, *
real
real
real
+, -, *
real
real
entero real
entero real
real
entero
div
entero
entero
entero
mod
entero
entero
entero
Tabla 1
Orden de evaluacin
Si la expresin contiene subexpresiones entre parntesis, las subexpresiones se evalan
primero.
Si la expresin contiene multiplicacin o divisin, estas operaciones son realizadas
trabajando de izquierda a derecha a travs de la expresin.
Las operaciones de suma y resta son llevadas a cabo de izquierda a derecha tambin.
En el orden de evaluacin se tiene en cuenta, lgicamente, la precedencia de los
operadores.
Operador
Prioridad
+-
* / mod div
- + (unario
Tabla 2
Funciones y predicados
Visual Prolog posee una gran cantidad de funciones y predicados matemticos para realizar
las ms variadas operaciones. La lista completa se ofrece en la Tabla 3.
Nombre
Descripcin
X mod Y
X div Y
abs(X)
Valor absoluto de X.
cos(X)
Coseno de X.
sin(X)
Seno de X.
tan(X)
Tangente de X.
arctan(X)
Arcotangente de X.
exp(X)
ln(X)
Logaritmo neperiano de X.
log(X)
Logaritmo en base 10 de X.
sqrt(X)
Raz cuadrada de X.
random(X)
random(X, Y)
round(X)
trunc(X)
val(domain,X)
Comparaciones
En Visual Prolog podemos comparar expresiones aritmticas, caracteres, cadenas de
caracteres y smbolos.
Las comparaciones de este tipo se realizan a travs de operadores relacionales. Ver Tabla 4.
Smbolo
Relacin
<
menor que
<=
igual que
>
mayor que
>=
<> o ><
distinto
Tabla 4
RBOLES
Un rbol es una estructura con una definicin puramente recursiva, ya que se puede
considerar como el elemento raz cuyos hijos son, a su vez, rboles. Si el rbol tiene
nicamente dos hijos se denomina rbol binario. Este modelo especfico de rbol se utiliza
mucho para resolver gran cantidad de problemas en aspectos de programacin.
Un rbol se puede considerar, a su vez, un caso particular de grafo, donde todos los
caminos son acclicos.
La Figura 1 muestra un ejemplo de rbol.
Figura 1
Ejemplo de rbol
Figura 2
rbol de anlisis de una frase en espaol
Como se observa, el uso de un predicado con dos argumentos en el caso de rbol binario o
N argumentos en el caso de rbol N-ario es una forma sencilla de representar un rbol.
Mediante objetos compuestos recursivos del tipo arbol(nodo, hijoizq, hijoder), donde
hijoizq e hijoder son tambin rboles, podemos representar un rbol binario. El rbol vaco
se representa a travs del hecho vacio:
arbol(1,arbol(2,arbol(4,vacio,vacio),arbol(5,vacio,vacio)),arbol(3,vacio,vacio))
En la seccin DOMAINS podemos crear un tipo rbol de enteros del modo siguiente:
mi_arbol= arbol(INTEGER, mi_arbol, mi_arbol); vacio
Operaciones con rboles representados mediante objetos compuestos recursivos
domains
arbol= nodo(integer, arbol, arbol); vacio
lista= integer*
predicates
concatenar(lista, lista, lista)
preorden(arbol, lista)
inorden(arbol, lista)
postorden(arbol, lista)
clauses
concatenar([],[],[]):-!.
concatenar([],L2,L2):-!.
concatenar(L1,[],L1):-!.
concatenar([X|Y],L2,[X|Aux]):-concatenar(Y,L2,Aux).
preorden(vacio,[]):-!.
preorden(nodo(X,Izq,Der),[X|L]):-preorden(Izq,L1),
preorden(Der,L2),
concatenar(L1,L2,L).
inorden(vacio,[]):-!.
inorden(nodo(X,Izq,Der),L):-inorden(Izq,L1),
inorden(Der,L2),
concatenar(L1,[X|L2],L).
postorden(vacio,[]):-!.
postorden(nodo(X,Izq,Der),L):-postorden(Izq,L1),
postorden(Der,L2),
concatenar(L1,L2,L3),
concatenar(L3,[X],L).
goal
inorden(nodo(1,nodo(2,nodo(4,vacio,vacio),nodo(5,vacio,vacio)),nodo(3,vacio,vacio)), L1),
preorden(nodo(1,nodo(2,nodo(4,vacio,vacio),nodo(5,vacio,vacio)),nodo(3,vacio,vacio)), L2),
postorden(nodo(1,nodo(2,nodo(4,vacio,vacio),nodo(5,vacio,vacio)),nodo(3,vacio,vacio)), L3).
LISTAS
Una lista se puede considerar como un caso particular de rbol del modo que se muestra en
la Figura 3.
Figura 3
Lista implementada en forma de rbol
A su vez, una lista se puede considerar de forma recursiva. Es decir, siempre est formada
por un elemento seguido de otra lista (ver Figura 4). Cuando la lista tienen un slo
elemento podemos considerar que est formada por dicho elemento y la lista vaca. Esta
definicin es muy interesante, ya que su conocimiento nos permitir llevar a cabo todos las
operaciones que se pueden realizar sobre las listas con poco esfuerzo.
Figura 4
Definicin recursiva de una lista
Hemos de recordar que en Prolog no existen estructuras para realizar bucles luego todo los
algoritmos que representemos se definirn de forma recursiva. El hecho de que la
implementacin de la lista sea tambin recursiva facilita la construccin de operaciones
sobre la misma.
Es necesario comprender este tipo de estructura para construir algoritmos eficientes. La
mayor parte de las operaciones que se realizan sobre una lista implica un recorrido de la
misma, luego hemos de centrarnos en conocer cmo se lleva a cabo este algoritmo
utilizando tcnicas de recursividad.
Una lista se puede especificar en un predicado o en un objetivo a travs de:
Las listas pueden ser homogneas o heterogneas, es decir, almacenar elementos del mismo
tipo, o elementos de distinto tipo.
Para definir un tipo de lista en particular es necesario declararla en la seccin DOMAINS.
lista= elementos* (lista de una dimensin)
lista2= elementos** (lista de dos dimensiones)
lista3= elementos*** (lista de tres dimensiones)...
Es interesante observar la sintaxis de definicin de una lista: elementos representa el
dominio o tipo de los elementos que componen la lista.
El tipo elementos puede representar un dominio simple, es decir, slo un tipo de elementos
se corresponde con dicho dominio o un dominio complejo, donde varios tipos de elementos
se corresponden con dicho dominio.
Por ejemplo, una lista homognea de elementos simples estara definida como:
lista= integer*
Una lista heterognea de elementos estara definida como:
listaenteros=integer*
elementos= i(integer); s(symbol); c(char); le(listaenteros)
lista= elementos*
Ejemplo:
domains
listaenteros= integer*
elementos= i(integer); c(char); s(symbol); le(listaenteros)
lista= elementos*
predicates
recorrer(lista)
clauses
recorrer([]):-!.
recorrer([X|Y]):-write(X), nl, recorrer(Y).
goal
recorrer([i(1),c('a'),s(pepe),i(5),c('b'),le([1,2,3])]).
Se observa que la lista puede contener cuatro tipo de elementos distintos: enteros,
caracteres, smbolos y listas de enteros. En la seccin de declaracin del dominio o tipo
elementos no podemos escribir:
elementos= integer; char; symbol; listaenteros
para expresar que dicho dominio agrupa a cuatro tipos de elementos distintos sino que la
sintaxis a utilizar es aquella que representa que elementos agrupa a cuatro tipos de objetos
compuestos distintos.
El resultado de la ejecucin de la meta es el siguiente:
i(1)
c('a')
s("pepe")
i(5)
c('b')
le([1,2,3])
yes
Las operaciones tpicas que se pueden realizar sobre listas son: la insercin de elementos al
principio, al final, en orden; borrado, bsqueda de elementos, recorrido, eliminacin de
duplicados y, en general, todas las de las que se pueden realizar sobre conjuntos de
elementos tales como: interseccin, unin, diferencia, pertenencia, comprobacin de lista
vaca, concatenacin, etc.
Las listas se pueden utilizar para implementar otras estructuras tales como listas circulares,
vectores, pilas, colas, rboles, grafos y matrices.
De cada estructura nos interesa saber cules son los algoritmos para acceder a ellas. Una
vez que conocemos, perfectamente, el tipo de operaciones que las definen, cualquier tipo de
implementacin es vlida. Por ejemplo, es frecuente usar una implementacin mediante
listas para plasmar matrices.
Por otro lado, es fundamental aplicar tcnicas de diseo descendente para resolver todos
nuestros problemas e implementar las estructuras necesarias en nuestras aplicaciones.
MATRICES
Podemos definir matrices a partir de listas, primero de 2 dimensiones y, ms tarde,
generalizar matrices de dimensin N.
En un lenguaje imperativo, recorrer una matriz de dos dimensiones implica el uso de un par
de bucles anidados, que proporcionan una complejidad computacional O(n2). Sin embargo,
en Prolog, no disponemos de este tipo de estructuras de control, por tanto, cualquier
operacin debe ser resuelta de forma recursiva mediante la declaracin formal de su
enunciado.
Un tratamiento elemento a elemento de las matrices tal y como se realiza en un lenguaje
imperativo no es adecuado en Prolog, por tanto, conviene entender la estructura matriz
como una lista de listas, y aplicar los algoritmos diseados sobre listas para resolver
problemas matriciales.
Una matriz de cuatro dimensiones se puede ver como la secuencia de un conjunto de
matrices de tres dimensiones, una matriz de tres dimensiones como un conjunto de matrices
de dos dimensiones, una matriz de dos dimensiones como un conjunto o lista de matrices
de una dimensin (vector o lista), por ltimo, un vector o lista no es ms que una secuencia
de elementos simples.
BIBLIOGRAFIA
UNIDAD I
http://es.wikipedia.org/wiki/Estilo_de_programaci%C3%B3n
http://programacionlogicayfuncional.wordpress.com/2014/02/12/estilos-deprogramacion/
http://programacionlogicayfuncional.wordpress.com/2014/02/12/evaluacionde-expresiones/
http://programacionlogicayfuncional.wordpress.com/2014/02/13/definicionde-funciones/
http://users.dcc.uchile.cl/~lmateu/CC10A/Apuntes/deffun/index.html
UNIDAD II
http://sistemasumma.com/2011/09/04/tipos-de-datos-en-haskell/
Funciones http://www.cs.us.es/cursos/lp/practicas/tema-001.pdf
(Piensa en Haskell. JIMENEZ Jos A., Creative Commons. Sevilla 2012.)
(Yet Another Haskell Tutorial. Daume, Hal. 2006)
UNIDAD III
Evalacin perezosa. https://www.cs.us.es/~jalonso/cursos/pd09/temas/tema-10-1x2.pdf
Evaluacin perezosa. http://prezi.com/lhnyd5gqlj_-/unidad-3-evaliacionperezosa/
UNIDAD IV
Programacin Lgica.
http://clubensayos.com/Tecnolog%C3%ADa/ProgramacionLogica/1777196.html
Repaso de Lgica de Primer Orden. http://web.ing.puc.cl/~marenas/iic326010/clases/repaso-lpo.pdf
http://es.scribd.com/doc/71607751/Metodos-de-Resolucion-y-Unificacion
http://gpd.sip.ucm.es/jaime/docencia/pl/sld.pdf
http://wwwg.eng.cam.ac.uk/mmg/teaching/artificialintelligence/nonflash/resolution6.htm
http://gpd.sip.ucm.es/jaime/docencia/pl/busqueda.pdf
Mucho más que documentos.
Descubra todo lo que Scribd tiene para ofrecer, incluyendo libros y audiolibros de importantes editoriales.
Cancele en cualquier momento.