Práctica 2: Programación funcional en Scheme¶
Antes de la clase de prácticas¶
-
Antes de empezar esta práctica es importante que revises la solución de la práctica 1. Puedes preguntar las dudas al profesor de prácticas.
-
Los siguientes ejercicios están basados en los conceptos de teoría vistos la semana pasada. Antes de la clase de prácticas debes repasar todos los conceptos y probar en el DrRacket todos los ejemplos del tema 2 Programación Funcional hasta el apartado 2.6 Listas incluido.
Ejercicios¶
Abre el DrRacket y crea el fichero practica2.rkt
en el que deberás
escribir todos los ejemplos y soluciones de los ejercicios que
hagas. Escribe en comentarios tu nombre y apellidos. Usa también
comentarios para separar secciones y realizar anotaciones. Incluye en
el fichero todo el código, ejemplos y resolución de ejercicios, que
hagas esta semana.
También debes añadir casos de prueba al código de todas las funciones que implementes, tal y como vimos al final del seminario de Scheme. Puedes usar algunos de los ejemplos de los enunciados, pero debes también construir algunos casos nuevos, con ejemplos creados por ti.
Siempre debes incluir casos de prueba
Los casos de prueba son un componente importante del código, ya que permiten guardar en el propio código una demostración de que éste funciona correctamente, así como unos ejemplos de cómo llamar a las funciones definidas.
Ejercicio 1¶
a) Implementa la función (binario-a-decimal b3 b2 b1 b0)
que reciba
4 bits que representan un número en binario y devuelva el número
decimal equivalente.
(binario-a-decimal 1 1 1 1) ; ⇒ 15
(binario-a-decimal 0 1 1 0) ; ⇒ 6
(binario-a-decimal 0 0 1 0) ; ⇒ 2
Nota: recuerda que para realizar esta conversión, se utiliza la siguiente fórmula:
n = b3 * 2ˆ3 + b2 * 2ˆ2 + b1 * 2ˆ1 + b0 * 2ˆ0
Para la implementación de la expresión debes utilizar la función expt
.
b) Implementa la función (binario-a-hexadecimal b3 b2 b1 b0)
que
reciba 4 bits de un número representado en binario y devuelva el
carácter correspondiente a su representación en hexadecimal.
(binario-a-hexadecimal 1 1 1 1) ; ⇒ #\F
(binario-a-hexadecimal 0 1 1 0) ; ⇒ #\6
(binario-a-hexadecimal 1 0 1 0) ; ⇒ #\A
Nota: para realizar esta conversión, como paso intermedio debes pasar primero el número binario a su representación decimal (utilizando la función definida en el apartado anterior) y después a su correspondiente hexadecimal.
Recuerda que la representación hexadecimal de los números decimales del 0 al 9 es el carácter correspondiente a ese número, y que el número decimal 10 se representa con el carácter A, el 11 con el B, y así sucesivamente hasta el 15 que es el F en hexadecimal.
Para la implementación de esta función auxiliar que pasa de decimal a
hexadecimal debes usar las funciones integer->char
y
char->integer
. En la función char->integer
los caracteres
consecutivos están asociados con números consecutivos. Por ejemplo, el
entero correspondiente al carácter #\A
es uno menos que el
correspondiente al carácter #\B
. Los caracteres de números y los de
letras no son consecutivos.
Ejercicio 2¶
El cifrado César es una técnica cifrado por sustitución en la que cada letra del
texto se codifica por la correspondiente desplazada un cierto número de
lugares. Por ejemplo, si usamos un desplazamiento de 5, el carácter #\c
se
codificaría por el carácter #\h
(el carácter 5 posiciones después de la #\c
en el alfabeto).
Vamos a cifrar y descifrar letras minúsculas y mayúsculas del alfabeto inglés
(26 caracteres: desde #\a ó #\A)
hasta #\z ó #\Z
). Vamos a trabajar con un
desplazamiento variable, positivo o negativo, dependiendo en que sentido rotemos
el alfabeto.
Define las funciones (cifra-caracter char desplazamiento)
y (descifra-caracter char
desplazamiento)
que implementen el cifrado anterior.
Para la implementación de las funciones anteriores debes definir y usar las siguientes funciones auxiliares:
(encuentra-indice char)
(encuentra-caracter indice)
(entre-az? char)
(rota-indice indice desplazamiento)
La función (rota-indice indice desplazamiento)
recibe el índice del carácter
original y calcula el índice del carácter cifrado.
Consejo: puedes usar la función modulo
ver documentación.
Analiza los siguientes ejemplos para entender mejor el funcionamiento de las funciones auxiliares y las funciones principales:
(encuentra-indice #\a) ; ⇒ 0
(encuentra-indice #\b) ; ⇒ 1
(encuentra-indice #\m) ; ⇒ 12
(encuentra-indice #\z) ; ⇒ 25
(encuentra-caracter 0) ; ⇒ #\a
(encuentra-caracter 1) ; ⇒ #\b
(encuentra-caracter 12) ; ⇒ #\m
(encuentra-caracter 25) ; ⇒ #\z
(entre-az? #\a) ; ⇒ #t
(entre-az? #\m) ; ⇒ #t
(entre-az? #\z) ; ⇒ #t
(entre-az? #\`) ; ⇒ #f
(entre-az? #\{) ; ⇒ #f
(rota-indice 4 12) ; ⇒ 16)
(rota-indice 4 24) ; ⇒ 2)
(rota-indice 4 -5) ; ⇒ 25)
(cifra-caracter #\c 5) ; ⇒ #\h)
(cifra-caracter #\z -1) ; ⇒ #\y)
(cifra-caracter #\j 40) ; ⇒ #\x)
(cifra-caracter #\D 3) ; ⇒ #\G)
(cifra-caracter #\ñ 3) ; ⇒ #\ñ)
(descifra-caracter #\d 3) ; ⇒ #\a)
(descifra-caracter #\y -1) ; ⇒ #\z)
(descifra-caracter #\x 40) ; ⇒ #\j)
(descifra-caracter #\G 3) ; ⇒ #\D)
(descifra-caracter #\tab 3) ; ⇒ #\tab)
Ejercicio 3¶
Implementa la función (menor-de-tres n1 n2 n3)
que reciba tres
números como argumento y devuelva el menor de los tres, intentando que
el número de condiciones sea mínima.
No debes utilizar la función min
.
Implementa dos versiones de la función:
- versión 1: usando la forma especial
if
- versión 2 (llámala
menor-de-tres-v2
): sin usar la forma especialif
, sino definiendo una función auxiliar(menor x y)
que devuelva el menor de dos números (en esta sí que deberías usarif
) y construyendo la funciónmenor-de-tres-v2
como una composición de llamadas a esta función auxiliar.
(menor-de-tres 2 8 1) ;; ⇒ 1
(menor-de-tres-v2 3 0 3) ;; ⇒ 0
Ejercicio 4¶
a) Supongamos las definiciones
(define (f x)
(cons x 2))
(define (g x y)
(cons x y))
Realiza la evaluación paso a paso de la siguiente expresión
(g (f (+ 2 1)) (+ 1 1))
mediante el modelo de sustitución, utilizando tanto el orden aplicativo y como el orden normal.
Escribe la solución entre comentarios en el propio fichero .rkt
de
la práctica.
b) Supongamos las definiciones
(define (func-1 x)
(/ x 0))
(define (func-2 x y)
(if (= x 0)
0
y))
Igual que en el apartado anterior, realiza la evaluación paso a paso de la siguiente expresión
(func-2 0 (func-1 10))
mediante el modelo de sustitución, utilizando tanto el orden
aplicativo y como el orden normal. Y escribe la solución entre
comentarios en el propio fichero .rkt
de la práctica.
Ejercicio 5¶
Implementa la función (cadenas-mayores lista1 lista2)
que recibe 2
listas con 3 cadenas y devuelve otra lista con las 3 cadenas de mayor
longitud, comparando las cadenas de cada posición de la
lista. En el caso en que las cadenas tengan la misma longitud, se
devuelve la cadena de la primera lista.
Pista
Puedes utilizar las funciones second
y third
que devuelven el
segundo y el tercer elemento de una lista.
(cadenas-mayores '("hola" "que" "tal") '("meme" "y" "adios")) ; ⇒ ("hola" "que" "adios")
(cadenas-mayores '("esto" "es" "lpp") '("hoy" "hay" "clase")) ; ⇒ ("esto" "hay" "clase")
Ejercicio 6¶
a) Supongamos que queremos programar un juego de cartas que usa la baraja francesa. Lo primero que debemos hacer es definir una forma de representar las cartas y funciones que trabajen con esa representación. En este ejercicio vamos a implementar esas funciones.
Representaremos una carta por un símbolo con dos letras: la primera indicará su número o figura y la segunda el palo de la carta, representado con el símbolo UTF correspondiente.
Símbolos UTF de los palos de la baraja francesa
Puedes copiar los siguientes símbolos UTF y pegarlos en el código fuente de la práctica: ♠, ♣, ♥ y ♦ (picas, tréboles, corazones y diamantes).
Por ejemplo:
(define tres-de-picas '3♠)
(define as-de-corazones 'A♥)
(define jota-de-diamantes 'J♦)
Debemos definir la función carta
que devuelve una pareja con el
valor correspondiente a su orden en la baraja francesa (un número) y
el nombre del palo de la carta (como símbolo, no como cadena).
(carta tres-de-picas) ; ⇒ (3 . Picas)
(carta as-de-corazones) ; ⇒ (1 . Corazones)
(carta 'K♣) ; ⇒ (12 . Tréboles)
Los valores de las cartas de la baraja francesa son:
A (As) ⇒ 1
J (Jota) ⇒ 10
Q (Reina) ⇒ 11
K (Rey) ⇒ 12
Para realizar el ejercicio debes definir en primer lugar las funciones
(obten-palo char)
y (obten-valor char)
que devuelven el palo y el
valor, dado un carácter. Y debes implementar la función carta
usando
estas dos funciones.
(obten-palo #\♠) ; ⇒ Picas
(obten-palo #\♥) ; ⇒ Corazones
(obten-valor #\3) ; ⇒ 3
(obten-valor #\J) ; ⇒ 10
Pista
Puedes utilizar las funciones (symbol->string simbolo)
que convierte un
símbolo en una cadena y (string-ref cadena pos)
que devuelve el
carácter de una cadena situado en una determinada posición.
b) Implementa la función (jugada-mano carta1 carta2 carta3)
que recibe 3 cartas de la
baraja francesa y devuelve una cadena indicando si la jugada de tres
cartas contiene una pareja (dos cartas con el mismo valor), un trío
(las tres cartas tienen el mismo valor) o nada (las tres cartas
son distintas) y también el valor de la pareja o del trío.
Para obtener los valores de las cartas debes implementar la función
(valor-carta carta)
.
Ejemplos:
(jugada-mano '3♥ '3♣ '3♥) ; ⇒ "trío de 3"
(jugada-mano 'K♦ '7♠ 'K♥) ; ⇒ "pareja de 12"
(jugada-mano '5♣ '4♣ '6♣) ; ⇒ "nada"
Números a cadenas
Puedes obtener una cadena correspondiente a un número usando la función
number->string
. Esta función solo la debes usar en este ejercicio.
Lenguajes y Paradigmas de Programación, curso 2023-24
© Departamento Ciencia de la Computación e Inteligencia Artificial, Universidad de Alicante
Domingo Gallardo, Cristina Pomares, Antonio Botía, Francisco Martínez