Está en la página 1de 20

¿QUÉ ES SCHEME?

Scheme es un dialecto de Lisp, un lenguaje multiplataforma de


programación funcional (impuro) de propósito general, creado
en 1975 por Guy L. Steele y Gerald Jay Sussman. A su vez,
Racket es un dialecto de Scheme y DrRacket es un IDE que se
utiliza como motor de ejecución y compilación.

La filosofía de Scheme es minimalista, este proporciona el


mínimo número posible de nociones primitivas, construyendo
todo lo demás a partir de un reducido número de abstracciones.
No necesita reglas de precedencia (orden de operaciones) en
su gramática, ya que utiliza notación prefija para todas las
llamadas a función.

Por otra parte, los procedimientos (funciones) son objetos de


primera clase. Ello permite la definición de funciones de
orden superior (funciones que reciben o retornan otras
funciones). También existen funciones anónimas (funciones
lambda).

Scheme utiliza ámbito estático (léxico). Cuando se dice que el


ámbito de una variable es una función, quiere decir que la
variable solo existe dentro del bloque de texto que define dicha
función.

Es un lenguaje que puede ser compilado o interpretado.


Compilado cuando se traduce el código fuente en un archivo
ejecutable para una determinada plataforma (MacOS, Windows,
Linux) o interpretado cuando se traduce línea a línea el código
fuente sin crear un archivo ejecutable.

Es un lenguaje de tipado dinámico, ya que no es necesario


definir el tipo de dato al declarar una variable. También es
fuertemente tipado, es decir, no permite realizar operaciones
entre variables de distinto tipo, a menos de que se haga una
conversión.

Es un lenguaje case-sensitive, ya que distingue entre


mayúsculas y minúsculas.
COMENTARIOS
Un comentario es un texto descriptivo (ignorado durante la
ejecución del programa), el cual sirve para facilitar el
entendimiento de un bloque de código.

Scheme permite agregar comentarios en una línea (; texto


desciptivo) o comentarios en varias líneas (#| texto descriptivo
|#).

; comentario en un línea.

#| comentario en
varias líneas. |#

EXPRESIONES Y NOTACIÓN PREFIJA


El elemento más importante en Scheme son las expresiones,
las cuales al ser evaluadas retornan un valor. Las expresiones
más básicas son las expresiones literales.

Las expresiones compuestas (las cuales pueden estar


anidadas) son formadas por subexpresiones encerradas entre
paréntesis. Aquí, la primera subexpresión identifica una
operación, las subexpresiones restantes son operandos de
dicha operación.

; ejemplos de expresión literal.


> 23
23

> 'gato
'gato

; ejemplos de expresión compuesta.


> (+ 23 42)
65

> (+ 14 (* 23 42))
VARIABLES Y ASIGNACIONES
Existen varias formas de declarar variables en Scheme. En
general, una variable global se define con la función (define
variable value), mientras que una variable local se define con la
función (let ((variable value) …) body). Se tiene además la
función (set! variable value) la cual permite asignar un nuevo
valor a una variable ya existente.

define una variable global. Asigna un identificador (id)


(define id value)
a un valor (value) específico.
define variables locales al cuerpo de la función let.
(let ((id value)
Inicializa varias variables y las usa en una expresión
(id value)
del cuerpo de let. Se recomienda su uso para valores
...)
independientes y donde no importa el orden de
exp)
evaluación.
define variables locales al cuerpo de la función let.
(let* ((id value)
Inicializa de forma secuencial varias variables y las usa
(id value)
en el cuerpo de let. Se recomienda su uso si hay una
...)
dependencia lineal entre los valores o el orden de
exp)
evaluación es importante.
(letrec ((id value) similar a let, pero permite hacer definiciones de
(id value) procedimientos recursivos. Se recomienda su uso
...) cuando hay una dependencia circular entre variables y
exp) el orden de evaluación no es importante.
asigna un nuevo valor a un identificador (id) ya
(set! id value) existente. Útil para actualizar un estado y para crear
estructuras recursivas.

Para declarar una variable de ámbito global se utiliza la


sintaxis (define varName value).

; declaración de variable global.


> (define nombre 'Juan)
> nombre
'Juan

Para declarar una variable de ámbito local (y evaluar una


expresión con dicha variable), se utiliza la forma (let ((var
value) (var2 value) ...) bodyLet). En este caso, el ámbito de la
variable se reduce al cuerpo de la función let.
#| declaración de variable local. Se declaran dos variables x y. Luego se
evalúa una expresión que suma ambas variables. Por fuera de la
expresión let, x y no existen. |#
> (let ((x 5)
(y 2))
(+ x y))
7

>x
error: x undefined

#| en las definiciones de let, no se puede hacer referencia a una variable


definida dentro del mismo let. |#
> (let ((x 3)
(y (+ x 1)))
(+ x y))
error: reference to undefined identifier: x

#| en este caso la definición de y utiliza el x definido globalmente y no el


x de let. |#
> (define x 5)
> (let ((x 3)
(y (+ x 2)))
(+ x y))

La función letrec es similar a let, solo que permite utilizar las


propias definiciones de forma recursiva, así el identificador
puede aparecer en la expresión de valor.

#| en las definiciones de letrec, si se puede hacer referencia a una


variable definida dentro del mismo let. |#
> (letrec ((x 3)
(y (+ x 1)))
(+ x y))
7

> (letrec ((fact (lambda (x)


(if (= x 0)
1
(* x (fact (- x 1)))))))
(fact 3))
6

Hay que reconocer además, que la funcionalidad de let se


puede implementar alternativamente con las funciones lambda.
> (let ((x 3)
(y (+ 3 2)))
(* x y))

; es equivalente a:

> ((lambda (x y)
(* x y)) 3 (+ 3 2))

La forma especial let* permite la definición secuecial de


variables. Es decir, si se define una variable en let, dicha
variable se puede utilizar para definir una variable posterior en
el mismo let.

> (let* ((a 0)


(b (+ a 1))
(c (+ b 1)))
(list a b c))
(0 1 2)

Después de definir una variable, se puede cambiar su valor con


la sintaxis (set! variable valor).

> (define x 10)


> (set! x 2)
>x
2

Nombre de variables
Recordar que Scheme es case-sensitive, por lo cual distingue
entre mayúsculas y minúsculas. El nombre de una variable
debe comenzar con un carácter alfabético, y puede contener
además, caracteres numéricos y otra serie de símbolos (! $ % &
/ * + - . : < = > ? @ _ ~). Siempre se debe procurar que el
nombre de la variable sea lo suficientemente descriptivo.

Los únicos caracteres no válidos en los identificadores son: ( )


[ ] { } , ' ' ; # | \. No se pueden utilizar identificadores que
correspondan con literales numéricos y tampoco están
permitidos los espacios dentro de los identificadores.
TIPOS DE DATOS EN SCHEME

1. Números
El tipo de dato number se puede clasificar en varios subtipos:
integer (e.g., 5), rational (e.g., 8/3), real (e.g., 5.0) y complex
(e.g., 3+4i).

Además, los números pueden ser exactos o inexactos. Un


número es inexacto si contiene parte decimal o si presenta un
exponente. En caso contrario es exacto. Es posible convertir un
número inexacto en exacto y viceversa a partir de las funciones
(inexact->exact a) y (exact->inexact a).

> (exact? 5.1)


#f

> (inexact->exact 5.1)


5 (56294995342131 / 562949953421312)

procedimientos numéricos
(+ a b ...) retorna a + b + ...
(- a b ...) retorna a - b - ...
(* a b ...) retorna a * b * ...
(/ a b ...) retorna a / b / ...
(sqrt a) retorna la raíz cuadrada de a
(abs a) retorna el valor absoluto de a
(sin a) retorna el seno de a
(cos a) retorna el coseno de a
(tan a) retorna la tangente de a
(asin a) retorna el arcoseno de a
(acos a) retorna el arcocoseno de a
(atan a) retorna el arcotangente de a
(max a b c ...) retorna el valor máximo entre los args
(min a b c ...) retorna el valor mínimo entre los args
(remainder a retorna el residuo de a / b
b)
(expt a b) retorna la potencia ab
(exp a) retorna la potencia ea
(log a) retorna el logaritmo en base 10 de a
(gcd a b c ...) retorna el máximo común divisor
(lcm a b c ...) retorna el mínimo común múltiplo
(floor a) retorna a redondeado al piso
(ceiling a) retorna a redondeado al techo
(truncate a) retorna la parte entera de a
(round a) retorna a redondeado
(random k) Retorna un número aleatorio entre 0 y k-1
procedimientos numéricos
(complex? a) retorna #t si a es un número complejo
(real? a) retorna #t si a es un número real
(rational? a) retorna #t si a es un número racional
(exact? a) retorna #t si a es un número exacto
(inexact? a) retorna #t si a es un número inexacto
(integer? a) retorna #t si a es un número entero
(even? a) retorna #t si a es un número par
(odd? a) retorna #t si a es un número impar
(zero? a) retorna #t si a es cero
(positive? a) retorna #t si a es un número positivo
(negative? retorna #t si a es un número negativo
a)
(number? a) retorna #t si a es un número

2. Booleanos
Son un tipo de dato lógico que puede tomar dos valores:
verdadero o falso, los cuales son representados como (#t
#true) y (#f #false) respectivamente. En general son false los
números que representan el 0, las cadenas vacías y las listas
vacías. Todo lo demás es true.

Los booleanos son útiles en expresiones condicionales, las


cuales se construyen a partir de operadores lógicos (and or not)
y de comparación (= < <= > >=).

Scheme presenta una serie de funciones denominadas


predicados, las cuales se identifican por la terminación del
nombre en -?- Estas funciones solo retornan true o false.

operadores lógicos
(and obj1 obj2 ...) retorna #t si todos los objs son #t
(or obj1 obj2 ...) retorna #t si algún obj es #t
(not obj) si obj es #t retorna #f
operadores de comparación
(= obj1 obj2) retorna #t si obj1 = obj2
(< obj1 obj2) retorna #t si obj1 < obj2
(<= obj1 obj2) retorna #t si obj1 <= obj2
(> obj1 obj2) retorna #t si obj1 > obj2
(>= obj1 obj2) retorna #t si obj1 >= obj2
predicados de igualdad
(= obj1 obj2) compara dos números
(equal? obj1 obj2) compara dos objetos cualquiera

predicados de tipo de dato


(symbol? obj) si obj es un símbolo retorna #t
(procedure? obj) si obj es una función retorna #t
(number? obj) si obj es un número retorna #t
(pair? obj) si obj es una pareja retorna #t
(null? obj) si obj es una lista vacía retorna #t
(boolean? obj) si obj es un booleano retorna #t
(vector? obj) si obj es un vector retorna #t
(char? obj) si obj es un carácter retorna #t
(string? obj) si obj es una cadena retorna #t
(list? obj) si obj es una lista retorna #t

3. Caracteres
Un carácter corresponde aproximadamente con un grafema
(letra, número, signo de puntuación u otro símbolo). En
Scheme, los caracteres (char) tienen la sintaxis #\char (e.g.,
#\a #\b #\c) y se asocian a valores escalares en el estándar
Unicode o ASCII.

predicado de tipo caracter


(char? obj) retorna #t si obj es de tipo caracter
conversión de tipos de datos
(char->integer char) retorna el código ASCII del carácter (char)
retorna un carácter según su código ASCII
(integer->char number)
(number)
conversión de caracteres
(char-upcase char) retorna char en mayúscula
(char-downcase char) retorna char en minúscula
comparación de caracteres
(char<? char1 ...) evalúa char1 < char2 < ... (distingue A-a)
(char-ci<? char1 ...) evalúa char1 < char2 < ... (no distingue A-a)
(char<=? char1 ...) evalúa char1 <= char2 <= ... (distingue A-a)
(char-ci<=? char1 ...) evalúa char1 <= char2 <= ... (no distingue A-a)
(char>? char1 ...) evalúa char1 > char2 > ... (distingue A-a)
(char-ci>? char1 ...) evalúa char1 > char2 > ... (no distingue A-a)
(char>=? char1 ...) evalúa char1 >= char2 >= ... (distingue A-a)
(char-ci>=? char1 ...) evalúa char1 >= char2 >= ... (no distingue A-a)
(char=? char1 ...) evalúa char1 = char2 = ... (distingue A-a)
(char-ci=? char1 ...) evalúa char1 = char2 = ... (no distingue A-a)
predicados de clasificación de caracteres
(char-upper-case? char) retorna #t si char está en mayúscula
(char-lower-case? char) retorna #t si char está en minúscula
(char-alphabetic? char) retorna #t si char es un carácter alfabético
(char-numeric? char) retorna #t si char es un carácter numérico
retorna #t si char es un símbolo matemático o de
(char-symbolic? char)
dinero
(char-punctuation? char) retorna #t si char es un signo de puntuación
retorna #t si char es un carácter de espacio en
(char-whitescape? char)
blanco
4. Cadenas de texto
Una cadena de texto es una secuencia finita de caracteres
delimitados por comillas dobles (e.g., "gato"). Cada carácter
dentro de la cadena tiene un índice que indica su posición, el
cual inicia en 0.

predicado de tipo cadena de caracteres


(string? obj) retorna #t si obj es una cadena de caracteres
creación de cadenas de caracteres
retorna una cadena con k caracteres iguales a
(make-string k char)
char
(string char1 ...) retorna una cadena con los caracteres indicados
retorna una subcadena de str que va desde start
(substring str start end)
a end
(string-copy str) retorna una nueva cadena, copia de str
retorna una cadena producto de concatenar
(string-append str1 ...)
varias str
modificación de cadenas de caracteres
(string-upcase str) retorna str en mayúscula sostenida
(string-downcase str) retorna str en minúsculas
(string-titlecase str) retorna str con mayúscula inicial en cada palabra
cambia la subcadena a por la subcadena b dentro
(string-replace str a b)
de str
(string-set! str k char) cambia char en la posición k de la cadena str
funciones entre listas y cadenas de caracteres
(string->list str) convierte la cadena str en una lista de caracteres
convierte una lista list en una cadena de
(list->string list)
caracteres
convierte una lista (cuyos elem. son str) en una
(string-join list)
cadena
convierte una cadena str en una lista (sep =
(string-split str sep) separador de los elementos en la lista, por
defecto espacio en blanco)
comparación de cadenas de caracteres
(string=? str1 ...) evalúa str1 = str2 = ... (distingue A-a)
(string-ci=? str1 ...) evalúa str1 = str2 = ... (no distingue A-a)
(string<? str1 ...) evalúa str1 < str2 < ... (distingue A-a)
(string-ci<? str1 ...) evalúa str1 < str2 < ... (no distingue A-a)
(string<=? str1 ...) evalúa str1 <= str2 <= ... (distingue A-a)
(string-ci<=? str1 ...) evalúa str1 <= str2 <= ... (no distingue A-a)
(string>? str1 ...) evalúa str1 > str2 > ... (distingue A-a)
(string-ci>? str1 ...) evalúa str1 > str2 > ... (no distingue A-a)
(string>=? str1 ...) evalúa str1 >= str2 >= ... (distingue A-a)
(string-ci>=? str1 ...) evalúa str1 >= str2 >= ... (no distingue A-a)
otras funciones útiles para cadenas de caracteres
(string-length str) retorna el número de caracteres de la cadena
retorna el carácter en la posición k de la cadena
(string-ref str k)
str
(string-prefix? str a) retorna #t si str comienza con la subcadena a
(string-suffix? str a) retorna #t si str termina con la subcadena a
(string-contains? str a) retorna #t si str contiene la subcadena a
5. Símbolos
Un símbolo, también denominado identificador, es un objeto
simple (pieza atómica) que consiste en una secuencia finita de
caracteres. En Scheme los símbolos se escriben según la
sintaxis 'symbol (e.g., 'luna)Se diferencia de las cadenas de
caracteres en que no puede contener espacios en blanco.

Los símbolos son más ligeros y eficientes que las cadenas de


caracteres, por lo cual, se recomienda su uso cada vez que se
pueda.

predicado de tipo símbolo


(symbol? obj) retorna #t si obj es un símbolo
comparación de símbolos
(symbol=? sym1 retorna #t si todos los símbolos (syms) son
sym2 ...) iguales
conversión entre símbolos y cadenas de caracteres
convierte el símbolo (sym) en una cadena de
(symbol->string sym)
caracteres
convierte la cadena de caracteres (str) en un
(string->symbol str)
símbolo

6. Parejas y listas
El tipo de dato compuesto más simple es la pareja: una entidad
formada por exactamente dos elementos de cualquier tipo.
Para definir una pareja, Scheme utiliza la función (cons elem1
elem2) (e.g., (cons 'pez #false)).

Una lista es una secuencia de parejas, en las que el primer


elemento es un dato cualquiera y el segundo elemento es una
lista y el último elemento una lista vacía, la cual se define con
la sintaxis '() o con las palabras clave empty o null (e.g., (cons 1
(cons 2 (cons 3 null)))). También se pueden crear listas con la
sintaxis '(obj1 obj2 ...) (e.g., '(2 4 6)) o utilizando la función (list
obj1 obj2 ...) (e.g., (list 1 3 5 7 9)).

predicado de tipo pareja y lista


(pair? obj) retorna #t si obj es una pareja
(list? obj) retorna #t si obj es una lista
(empty? list) retorna #t si list es una lista vacía
(null? list) retorna #t si list es una lista vacía
procedimientos sobre parejas
(cons obj1 obj2) crea una pareja a partir de dos elementos
(car pair) retorna el primer elemento de la pareja
(cdr pair) retorna el segundo elemento de la pareja
procedimientos sobre listas
(cons obj list) crea una lista a partir de un objeto y otra lista
(list obj1 ...) crea una lista a partir de varios elementos
(car list) ~ (first list) retorna el primer elemento de la lista
(cdr list) ~ (rest list) retorna toda la lista sin el primer elemento
(last list) retorna el último elemento de la lista
(range end) crea una lista que va desde 0 hasta end-1.
crea una lista que va desde start hasta end-1
(range start end step)
saltando entre elementos.
(append list1 ...) combina dos o más listas entre sí
(reverse list) invierte el orden de los elementos de una lista
(length list) retorna el número de elementos de la lista
retorna el elemento en la posición k de la lista
(list-ref list k)
señalada
(list-tail list k) retorna una lista sin los k primeros elementos
(member obj list) retorna una sublista cuyo primer elemento es obj
retorna una lista ordenada según una función de
(sort list function)
comparación (e.g., > string<?)
(remove elem list) remueve el primer elem que se encuentre en list.
remueve el todos los elem que se encuentren en
(remove elem list =)
list.
(remove-duplicated list) remueve todos los elementos duplicados en list.

7. Procedimientos
Una función o procedimiento se considera un tipo de dato
primitivo. Un dato primitivo es aquel que puede ser el valor de
una variable, un argumento de una función, el valor que
devuelve una función o incluso el componente de una
estructura de datos mayor.

Los tipos de datos primitivos se pueden manejar directamente


sin la necesidad de darles un nombre. En el caso de los
procedimientos, esto se hace utilizando las funciones lambda,
la cual construye una función anónima (con sus argumentos y
su cuerpo) y retorna un resultado.

(lambda (arg1 arg2 ...)


se define una función anónima.
(body))
se define una función anónima y se
((lambda (arg1 arg2 ...)
pasan los valores que reemplazan a los
(body)) value1 value2 ...)
parámetros en la llamada a la función.
(define (funcName arg1 arg2 ...) se define una función, la cual recibe un
(body))
nombre y una serie de argumentos.
llamada a una función por medio de su
(funcName arg1 arg2 ...)
nombre y sus argumentos.

CONDICIONALES

(if condición
Se evalúa una condición, si es verdadera se ejecuta la
expresionTrue
expresionTrue, si es falsa se ejecuta la expresionFalse.
expresionFalse)
(cond
(condicion1 exp1) Corresponde a varios if anidados. Ejecuta la exp de la
(condicion2 exp2) primera condición evaluada como verdadera. Si
... ninguna condición se cumple, retorna la exp asociada
(else expn)) al else.

(case (clave)
Permite ejecutar una acción (exp) entre varias en
((value1) exp1)
función del valor (value) de una expresión (clave). Si el
((value2) exp2)
valor de la clave no corresponde a ninguno, se ejecuta
...
la expresión else.
(else expn))

1. Condicional if
La expresión (if condición exp-verdad exp-falso) permite
evaluar una condición y retornar una expresión si dicha
condición es verdadera o falsa (la expresión en caso de que la
condición sea falsa es opcional, se puede omitir).

> (define x 3)

> (if (> x 5)


"mayor que 5"
"menor que 5")

"menor que 5"

2. Condicionales anidados - Cond


El condicional cond permite evaluar varias condiciones y
retorna el valor de la expresión asociada a la primera condición
verdadera. Si ninguna condición es verdadera, retorna la
expresión asociada al else.

Su sintaxis es la siguiente:
(cond
(condición1 expresión1)
(condición2 expresión2)
...
(else expresiónElse))

> (cond
((> 2 5) "2 es mayor que 5")
((< 1 3) "1 es menor que 3")
((= 3 7) "3 es igual que 7")
(else "ninguna condición es cierta"))

"1 es menor que 3"

3. Condicional Case
La sentencia case permite ejecutar una de entre varias
acciones en función del valor de una expresión. Primero se
evalúa la expresión clave, dando como resultado un número,
luego se recorren las varias opciones dentro de la estructura
buscando el número que coincida con uno de los valores
disponibles. Cuando se encuentra la primera coincidencia, se
ejecuta la expresión asociada. Si no se encuentra ninguna
coincidencia con ningún valor, se ejecuta la expresión asociada
a la sección else.

Su sintaxis es la siguiente:

(case (expresion clave)


((valor1) expresión1)
((valor2) expresión2)
...
(else expresiónElse))
> (define f
(lambda (x)
(case x
((1 3 5 7 9) 'impar)
((0 2 4 6 8) 'par)
(else 'fuera-de-rango))))

> (f 4)

BUCLES Y RECURSIÓN
En programación funcional pura no existe el concepto de bucle,
sin embargo, no es necesario si se tiene la recursión. Una
función es recursiva cuando se llama así misma.

Cualquier función en donde se necesite repetir una sentencia


un número de veces (o hasta que se cumpla una condición) se
puede expresar de forma recursiva.

; ejemplo de bucle for en Python.


def factorial(x):
result = 1
for i in range(1, x+1):
result *= i
return result

; misma función en Scheme, usando recursión.


> (define (factorial x)
(if (= x 0)
1

; ejemplo de bucle while en C.


> suma-hasta (k) {
suma=0;
j=0;
while (j<=k) {
suma = suma+j;
j++;
}
}

; misma función en Scheme, usando recursión.


> (define (suma-hasta k)
(if (= k 0)
0
; ejemplo de recursión por posposición de trabajo.
> (define (longitud L)
(cond
[(empty? L) 0]
[else (+ 1 (longitud (rest L)))]))

; al evaluar (longitud (list "a" "b" "c")) se da este proceso:


-> (longitud (list "a" "b" "c"))
= (+ 1 (longitud (list "b" "c")))
= (+ 1 (+ 1 (longitud (list "c"))))
= (+ 1 (+ 1 (+ 1 (longitud (list)))))
= (+ 1 (+ 1 (+ 1 0)))
= (+ 1 (+ 1 1))
= (+ 1 2)
=3

; se apilan todos los cálculos y todas las sumas quedan pospuestas

; ejemplo de recursión de cola.


> (define (longitud L)
; función local longitud -aux:
(define (longitud-aux L longitud-actual)
(cond
[(empty? L) longitud-actual]
[else (longitud-aux (rest L) (+ longitud-actual 1))]))
; este es el cuerpo de longitud, que llama a longitud-aux:
(longitud-aux L 0))

; ahora veamos el cálculo de (longitud (list "a" "b" "c")):


-> (longitud (list "a" "b" "c"))
= (longitud-aux (list "a" "b" "c") 0)
= (longitud-aux (list "b" "c") 1)
= (longitud-aux (list "c") 2)
= (longitud-aux (list) 3)
=3

; note que no hay retornos pendientes en ningún momento, tampoco


hay cálculos que queden pendientes en cada paso de la recursión. En

BLOQUE DE CÓDIGO SECUENCIAL


En el paradigma funcional, no existe el concepto de secuencia
de instrucciones, pero como Scheme es un lenguaje funcional
impuro, si dispone de esta característica. La secuencia de
instrucciones está presente por defecto en los bloques lambda,
cond, case y let. Para aquellos casos en los que se quiera definir
una secuencia de instrucciones de utiliza el bloque begin.
ejecuta de manera secuencial las
distintas expresiones, retornando el
(begin exp1 exp2 ...) valor de la última expresión evaluada.
Esto permite establecer varias
instrucciones en una función.

ENTRADA Y SALIDA
procedimientos de entrada
lee lo que se escribe por teclado. Convierte el input en un
(read) dato de tipo símbolo (por lo cual si se escriben varias
palabras, solo guarda la primera)
lee lo que se escribe por teclado. Convierte el input en un
(read-char)
dato de tipo caracter
procedimientos de salida
(newline) imprime en pantalla una línea en blanco
(display obj) imprime en pantalla el objeto especificado

ITERACIÓN
En el paradigma funcional no existe el concepto de iteración,
sin embargo, este es implementado por medio de la
recursividad. Scheme, al ser un lenguaje de programación
funcional impuro, tiene una estructura de iteración simple,
denominada do.

Las variables (var) se ligan inicialmente al valor (val1)


y son re-ligadas a un nuevo valor (val2) en cada
(do ((var val1 val2)
iteración posterior. En cada paso se evalúa una
...)
condición (test). Si la condición es verdadera se evalúa
(test res ...)
en secuencia (res) y se retorna el valor de la última
exp ...)
expresión (res). Si la condición es falsa, se evalúa en
secuencia (exp) y se vuelve a iterar.

; ejemplo de iteración simple con do.


> (define factorial
(lambda (n)
(do ( (i n (- i 1))
(a 1 (* a i)))
((zero? i) a))))

> (factorial 3)
Para ejecutar (factorial 3):
- En la primera iteración i = 3 y a = 1. Como la condición (zero? i) es falsa y no se tiene
una expresión (exp), se realiza entonces una segunda iteración.
- En la segunda iteración i = 2 y a = 3. Como la condición (zero? i) es falsa y no se tiene
una expresión (exp), se realiza entonces una tercera iteración.
- En la tercera iteración i = 1 y a = 6. Como la condición (zero? i) es falsa y no se tiene
una expresión (exp), se realiza entonces una cuarta iteración.
En la cuarta iteración i = 0 y a = 6. Como la condición (zero? i) es verdadera, se retorna
la expresión (res) la cual equivale a a = 6. Por o cual la respuesta de (factorial 3) es 6.

; ejemplo de iteración simple con do.


> (define divisores
(lambda (n)
(do ((i 1 (+ i 1))
(ls '()
(if (integer? (/ n i))
(cons i ls)
ls)))
((> i n) ls))))

> (divisores 6)

Para ejecutar (divisores 6):


- En la primera iteración n=6 i=1 y ls='(). Como la condición (> i n) es falsa y no se tiene
una expresión (exp), se realiza entonces una segunda iteración.
- En la segunda iteración n=6 i=1 y ls=(cons 1 '()). Como la condición (> i n) es falsa y
no se tiene una expresión (exp), se realiza entonces una tercera iteración.
- En la tercera iteración n=6 i=2 y ls=(cons 2 (cons 1 '())). Como la condición (> i n) es
falsa y no se tiene una expresión (exp), se realiza entonces una cuarta iteración.
- En la cuarta iteración n=6 i=3 y ls=(cons 3 (cons 2 (cons 1 '()))). Como la condición (> i
n) es falsa y no se tiene una expresión (exp), se realiza entonces una quinta iteración.
- En la quinta iteración n=6 i=4 y ls=(cons 3 (cons 2 (cons 1 '()))). Como la condición (> i
n) es falsa y no se tiene una expresión (exp), se realiza entonces una sexta iteración.
- En la sexta iteración n=6 i=5 y ls=(cons 3 (cons 2 (cons 1 '()))). Como la condición (> i
n) es falsa y no se tiene una expresión (exp), se realiza entonces una séptima iteración.
- En la séptima iteración n=6 i=6 y ls=(cons 6 (cons 3 (cons 2 (cons 1 '())))). Como la
condición (> i n) es falsa y no se tiene una expresión (exp), se realiza entonces una
octava iteración.
- En la octava iteración n=6 i=7 y ls=(cons 6 (cons 3 (cons 2 (cons 1 '())))). Como la
condición (> i n) es verdadera, se retorna la expresión (res) la cual equivale a ls=(cons 6
(cons 3 (cons 2 (cons 1 '())))). Por o cual la respuesta de (divisores 6) es '(6 3 2 1).

FUNCIONES QUE ITERAN SOBRE LISTAS


retorna una nueva lista producto de
aplicar una función sobre cada elemento
(map function list)
de la lista original. La función solo puede
recibir un parámetro.
retorna #t si el resultado de evaluar la
(andmap function list) función sobre cada elemento de la lista
es #t. La función debe ser un predicado.
(ormap function list) retorna #t si la función se evalúa a
verdadero para alguno de los elementos
de la lista. La función debe ser un
predicado.
retorna los elementos de la lista que
(filter function list) evalúan como #t a la función
(predicado).
se utiliza para recorrer la lista y
(for-each function list)
mostrarla en pantalla.
permite definir funciones con un número
(apply function list) arbitrario de parámetros. Su resultado
equivale a (function arg1 arg2 …).

Las funciones map, andmap, ormap, filter y for-each pueden


aceptar múltiples listas (todas con la misma longitud), teniendo
en cuenta que la función debe aceptar un parámetro por cada
lista.
; ejemplo de función map.
> > (map sqr '(1 2 3 4 5 6 7 8 9))
'(1 4 9 16 25 36 49 64 81)

> (map (lambda (x) (+ x 1)) (list 1 2 3 4 5 6 7 8 9))


'(2 3 4 5 6 7 8 9 10)

> (andmap symbol? (list 'a 'b 'c 'd))


#t

> (ormap (lambda(x) (and (real? x) (positive? x))) (list -1 -2 3 -4))


#t

; suma solo si los argumentos son enteros positivos.


> (define (sumaInt+ a b c)
(if (andmap (lambda(x) (and (integer? x) (positive? x)))
(list a b c))
(+ a b c)
"Los parámetros no son enteros positivos "))

> (sumaInt+ -2 2 1)
"Los parámetros no son enteros positivos "

> (filter string? (list "andres" 'juan 12 -4 "ana" 'fd))


'("andres" "ana")

; deja solo los elementos que sean impares y múltiplos de 3.


> (filter (lambda(x) (and (odd? x) (= 0 (remainder x 3))))
(list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
'(3 9 15)

> (for-each (lambda(x) (printf "~a \n" x)) (list 'a 'b 'c 'd))
a
b
c
d

> (map + '(1 2 3) '(4 5 6))


'(5 7 9)
; en Scheme se pueden crear funciones que tomen un número variable
de argumentos. Una manera es indicar el penúltimo argumento como un
punto y el último elemento como el resto de la lista. Esto le indica a
Scheme que los argumentos se empaquetan en una lista cuando el
procedimiento es invocado.
> (define (suma . args)
(apply + args))

> (suma 6 4 4)
14

; otra forma es utilizar el identificador args como argumento en una


función lambda. Acá se usa la variable args para almacenar la lista de
argumentos.
> ((lambda args (apply + args)) 2 4 6 4)
16

; para crear funciones con parámetros opcionales se usa la sintaxis


arg1 . arg2. Los argumentos antes del punto son obligatorios. El resto de
argumentos se guarda en una lista y se pasa como arg2. Si no se pasan

También podría gustarte