I1M2015: El algoritmo de Luhn en Haskell
En la tercera parte de la clase de hoy de Informática de 1º del Grado en Matemáticas hemos comentado las soluciones a los ejercicios de la relación 8 sobre el algoritmo de Luhn.
Los ejercicios y su solución se muestran a continuación
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
-- --------------------------------------------------------------------- -- § Introducción -- -- --------------------------------------------------------------------- -- El objetivo de esta relación es estudiar un algoritmo para validar -- algunos identificadores numéricos como los números de algunas tarjetas -- de crédito; por ejemplo, las de tipo Visa o Master Card. -- -- El algoritmo que vamos a estudiar es el algoritmo de Luhn consistente -- en aplicar los siguientes pasos a los dígitos del número de la -- tarjeta. -- 1. Se invierten los dígitos del número; por ejemplo, [9,4,5,5] se -- transforma en [5,5,4,9]. -- 2. Se duplican los dígitos que se encuentra en posiciones impares -- (empezando a contar en 0); por ejemplo, [5,5,4,9] se transforma -- en [5,10,4,18]. -- 3. Se suman los dígitos de cada número; por ejemplo, [5,10,4,18] -- se transforma en 5 + (1 + 0) + 4 + (1 + 8) = 19. -- 4. Si el último dígito de la suma es 0, el número es válido; y no -- lo es, en caso contrario. -- -- A los números válidos, los llamaremos números de Luhn. -- --------------------------------------------------------------------- -- Ejercicio 1. Definir la función -- digitosInv :: Integer -> [Integer] -- tal que (digitosInv n) es la lista de los dígitos del número n. en -- orden inverso. Por ejemplo, -- digitosR 320274 == [4,7,2,0,2,3] -- --------------------------------------------------------------------- digitosInv :: Integer -> [Integer] digitosInv n | n < 10 = [n] | otherwise = (n `rem` 10) : digitosInv (n `div` 10) -- --------------------------------------------------------------------- -- Ejercicio 2. Definir la función -- doblePosImpar :: [Integer] -> [Integer] -- tal que (doblePosImpar ns) es la lista obtenida doblando los -- elementos en las posiciones impares (empezando a contar en cero y -- dejando igual a los que están en posiciones pares. Por ejemplo, -- doblePosImpar [4,9,5,5] == [4,18,5,10] -- doblePosImpar [4,9,5,5,7] == [4,18,5,10,7] -- --------------------------------------------------------------------- -- 1ª definición (por recursión) doblePosImpar :: [Integer] -> [Integer] doblePosImpar [] = [] doblePosImpar [x] = [x] doblePosImpar (x:y:zs) = x : 2*y : doblePosImpar zs -- 2ª definición (por recursión) doblePosImpar2 :: [Integer] -> [Integer] doblePosImpar2 (x:y:zs) = x : 2*y : doblePosImpar2 zs doblePosImpar2 xs = xs -- 3ª definición (por comprensión) doblePosImpar3 :: [Integer] -> [Integer] doblePosImpar3 xs = [f n x | (n,x) <- zip [0..] xs] where f n x | odd n = 2*x | otherwise = x -- --------------------------------------------------------------------- -- Ejercicio 3. Definir la función -- sumaDigitos :: [Integer] -> Integer -- tal que (sumaDigitos ns) es la suma de los dígitos de ns. Por -- ejemplo, -- sumaDigitos [10,5,18,4] = 1 + 0 + 5 + 1 + 8 + 4 = -- = 19 -- --------------------------------------------------------------------- -- 1ª definición (por comprensión): sumaDigitos :: [Integer] -> Integer sumaDigitos ns = sum [sum (digitosInv n) | n <- ns] -- 2ª definición (por recursión): sumaDigitos2 :: [Integer] -> Integer sumaDigitos2 [] = 0 sumaDigitos2 (n:ns) = sum (digitosInv n) + sumaDigitos2 ns -- --------------------------------------------------------------------- -- Ejercicio 4. Definir la función -- ultimoDigito :: Integer -> Integer -- tal que (ultimoDigito n) es el último dígito de n. Por ejemplo, -- ultimoDigito 123 == 3 -- ultimoDigito 0 == 0 -- --------------------------------------------------------------------- ultimoDigito :: Integer -> Integer ultimoDigito n = n `rem` 10 -- --------------------------------------------------------------------- -- Ejercicio 5. Definir la función -- luhn :: Integer -> Bool -- tal que (luhn n) se verifica si n es un número de Luhn. Por ejemplo, -- luhn 5594589764218858 == True -- luhn 1234567898765432 == False -- --------------------------------------------------------------------- luhn :: Integer -> Bool luhn n = ultimoDigito (sumaDigitos (doblePosImpar (digitosInv n))) == 0 |
El codigo correspondiente se encuentra en GitHub.