Buen, aca aporto con el ejercicio 3 y 4 dde la practica 7. Funcionan (por lo menos no los pude romper), pero me parece que la implementacion es, hablando formalmente, exageradamente fea. Los invito a tirar ideas mejores para estos dos ejercicios
(el 20 que parece arbitrario en "ej3 x = mainRepeticiones (listaRepeticiones x 20)", es efectivamente, arbitrario. Lo use para generar una lista de 20 "reducciones" y despues buescar ahi los repetidos)
---ej 3
ej3::Int->Int
ej3 x = mainRepeticiones (listaRepeticiones x 20)
mainRepeticiones::[Int] -> Int
mainRepeticiones [] = -1
mainRepeticiones (x:xs) | x `elem` xs = x
|otherwise = mainRepeticiones xs
listaRepeticiones::Int->Int->[Int]
listaRepeticiones x 0 = []
listaRepeticiones x y = x:(listaRepeticiones (reducir x) (y-1))
reducir::Int->Int
reducir 0 = 0
reducir x = digitosMult x
digitosMult::Int->Int
digitosMult 0 = 2
digitosMult x = (x `mod` 10) * (digitosMult (x `div` 10))
(En este creo q hay q importar List para usar la funcion reverse, fue de vago nomas)
--- Ej 4
ej4::[Int]->[Int]
ej4 x = ej4bis (sublistas x)
ej4bis::[[Int]]->[Int]
ej4bis [x] = x
ej4bis (x:xs:xss) | sumas x >= sumas xs = ej4bis(x:xss)
| otherwise = ej4bis(xs:xss)
sumas::[Int]->Int
sumas [] = 0
sumas (x:xs) = x + sumas xs
sublistas::[Int]->[[Int]]
sublistas [] = []
sublistas (x:xs) =(sublista (x:xs))++(sublistas xs)
sublista::[Int]->[[Int]]
sublista [] = []
sublista x = x:(sublista (sinUltimo x) )
sinUltimo::[Int]->[Int]
sinUltimo x = reverse(tail(reverse x))
en el ej3 lo que se pide es la posicion de la primer repetición, y no cual es número que se repite, y basado en como lo hiciste se podria cambiar esta linea
ej3:: Integer -> Integer
ej3 n = mainRepeticiones (listaRepeticiones n 20) 0
mainRepeticiones :: [Integer] -> Integer -> Integer
mainRepeticiones (x:xs) n
| x `elem` xs = n
| otherwise = mainRepeticiones xs (n+1)
Lo que no me salió, fue hacerlo sin tener que pasarle un número de repeticiones (ahora el 20). Habría que verificar si el número acutal, está en la lista que se va creando en el momento, pero no se como obtener esa lista.
Yo lo hice de otra forma y zafé de pasarle un número de repeticiones. Parece muuuy choclo pero la idea es:
Buscar la forma de dar el primer numero repetido de la cadena de reducciones (esto lo hace empezando a reducir y "almacenando" las reducciones hasta el momento, con cada reduccion se fija si el resultado ya pertenece a la lista de reducciones almacenadas)
Devolver la cantidad de veces que hay que reducir el numero original para que de el numero que después va a dar repetido.
nota: sigue siendo muy arcaica la forma de calcular el producto de las cifras, debería darme vergüenza.
archivo hs para bajar (me encanta hacer eso jaja) acá
CÓDIGO:
nreduc :: Integer -> Integer --Dice cuantas veces hay que reducir para que de el primer numero que se repite en la cadena de reducciones
nreduc n = (primeraAparicion n (valorRep n) 1)
--AUXILIARES--
prodCifras :: Integer -> Integer --Producto de las cifras
prodCifras n = auxProd n (cifras n)
reduc :: Integer -> Integer --Reduce un numero
reduc n = (prodCifras n) * 2
reducNVeces :: Integer -> Integer -> Integer --Reduce un numero n veces
reducNVeces z 0 = z
reducNVeces z 1 = reduc z
reducNVeces z n = reduc (reducNVeces z (n-1))
reducHastaN :: Integer -> Integer -> [Integer] --La lista de las reducciones hasta la n-esima
reducHastaN z 0 = [z]
reducHastaN z n = (reducHastaN z (n-1)) ++ [(reducNVeces z n)]
reduccionRepetida :: Integer -> Integer -> Bool --Dice si la reducción n-esima ya pertenece a la lista parcial de reducciones
reduccionRepetida z n = elem (reducNVeces z n) (reducHastaN z (n-1))
auxValorRep :: Integer -> Integer -> Integer --Auxiliar para la funcion siguiente, recorre desde 1
auxValorRep z n
| reduccionRepetida z n = reducNVeces z n
| otherwise = (auxValorRep z (n+1))
valorRep :: Integer -> Integer --Devuelve el primer valor repetido de la lista de reducciones
valorRep z = auxValorRep z 1
primeraAparicion :: Integer -> Integer -> Integer -> Integer --Dice cuantas veces hay que reducir un numero z hasta que de r (el n es una variable que va probando)
primeraAparicion z r n
| reducNVeces z n == r = n
| otherwise = primeraAparicion z r (n+1)
--AUXILIARES MENOS IMPORTANTES--
auxProd :: Integer -> Integer -> Integer
auxProd n m
| m == 1 = nCifra n 1
| otherwise = (nCifra n m) * (auxProd n (m-1))
nCifra :: Integer -> Integer -> Integer
nCifra z n = div (mod z (10^n) - mod z (10^(n-1))) (10^(n-1))
cifras :: Integer -> Integer
cifras 0 = 1
cifras n = auxcif n 1
auxcif :: Integer -> Integer -> Integer
auxcif n m
| div n (10^m) < 1 && div n (10^(m-1))>= 1 = m
| otherwise = auxcif n (m+1)