{"id":1752,"date":"2011-12-07T23:27:49","date_gmt":"2011-12-07T23:27:49","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=1752"},"modified":"2013-03-08T05:48:58","modified_gmt":"2013-03-08T05:48:58","slug":"i1m2011-ejercicios-de-definiciones-por-recursion-y-comprension-y-sobre-cadenas-en-haskell","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/i1m2011-ejercicios-de-definiciones-por-recursion-y-comprension-y-sobre-cadenas-en-haskell\/","title":{"rendered":"I1M2011: Ejercicios de definiciones por recursi\u00f3n y comprensi\u00f3n y sobre cadenas en Haskell"},"content":{"rendered":"<p>La clase de hoy de <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-11\">Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas<\/a> hemos comentando las soluciones de ejercicios de las dos primeras partes de la <a href=\"https:\/\/www.glc.us.es\/~jalonso\/ejerciciosI1M2011G1\/images\/0\/0a\/Rel_9.hs\">9\u00aa relaci\u00f3n<\/a>. <\/p>\n<p>La 1\u00aa parte contiene ejercicios con definiciones por comprensi\u00f3n y recursi\u00f3n. En concreto, se estudian funciones para calcular<\/p>\n<ul>\n<li> la compra de una persona agarrada y\n<li> la divisi\u00f3n de una lista num\u00e9rica seg\u00fan su media.\n<\/ul>\n<p>La 2\u00aa parte contiene ejercicios sobre cadenas. En concreto, se estudian funciones para calcular<\/p>\n<ul>\n<li> la suma de los d\u00edgitos de una cadena,\n<li> la capitalizaci\u00f3n de una cadena,\n<li> el t\u00edtulo con las reglas de may\u00fasculas iniciales,\n<li> la b\u00fasqueda en crucigramas,\n<li> las posiciones de un car\u00e1cter en una cadena y\n<li> si una cadena es una subcadena de otra.\n<\/ul>\n<p>Estos ejercicios corresponden a los temas <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-11\/temas\/tema-5.pdf\">5<\/a>, <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-11\/temas\/tema-6.pdf\">6<\/a> y <a href\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-11\/temas\/tema-7.pdf\">7<\/a>.   <\/p>\n<p>Los ejercicios, y sus soluciones, se muestran a continuaci\u00f3n:<br \/>\n<!--more--><\/p>\n<pre lang=\"haskell\">\r\n-- ---------------------------------------------------------------------\r\n-- Importaci\u00f3n de librer\u00edas auxiliares                                --\r\n-- ---------------------------------------------------------------------\r\n\r\nimport Data.Char\r\nimport Data.List\r\nimport Test.QuickCheck\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Definiciones por comprensi\u00f3n y recursi\u00f3n                           --\r\n-- ---------------------------------------------------------------------\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 1.1. Una persona es tan agarrada que s\u00f3lo compra cuando le\r\n-- hacen un descuento del 10% y el precio (con el descuento) es menor o\r\n-- igual que 199. \r\n-- \r\n-- Definir, usando comprensi\u00f3n, la funci\u00f3n\r\n--    agarrado :: [Float] -> Float\r\n-- tal que (agarrado ps) es el precio que tiene que pagar por una compra\r\n-- cuya lista de precios es ps. Por ejemplo,\r\n--    agarrado  [45.00, 199.00, 220.00, 399.00]  ==  417.59998\r\n-- ---------------------------------------------------------------------\r\n\r\nagarrado :: [Float] -> Float\r\nagarrado ps = sum [p * 0.9 | p <- ps, p * 0.9 <= 199]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 1.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    agarradoRec :: [Float] -> Float\r\n-- tal que (agarradoRec ps) es el precio que tiene que pagar por una compra\r\n-- cuya lista de precios es ps. Por ejemplo,\r\n--    agarradoRec  [45.00, 199.00, 220.00, 399.00]  ==  417.59998\r\n-- ---------------------------------------------------------------------\r\n\r\nagarradoRec :: [Float] -> Float\r\nagarradoRec [] = 0\r\nagarradoRec (p:ps)\r\n    | precioConDescuento <= 199 = precioConDescuento + agarradoRec ps\r\n    | otherwise                 = agarradoRec ps\r\n    where precioConDescuento = p * 0.9 \r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 1.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- similares; es decir, el valor absoluto de su diferencia es menor que\r\n-- una d\u00e9cima. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_agarrado :: [Float] -> Bool\r\nprop_agarrado xs = abs (agarradoRec xs - agarrado xs) <= 0.1\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_agarrado\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.1. La funci\u00f3n \r\n--    divideMedia :: [Double] -> ([Double],[Double])\r\n-- dada una lista num\u00e9rica, xs, calcula el par (ys,zs), donde ys \r\n-- contiene los elementos de xs estrictamente menores que la media, \r\n-- mientras que zs contiene los elementos de xs estrictamente mayores \r\n-- que la media. Por ejemplo, \r\n--    divideMedia [6,7,2,8,6,3,4] ==  ([2.0,3.0,4.0],[6.0,7.0,8.0,6.0])\r\n--    divideMedia [1,2,3]         ==  ([1.0],[3.0])\r\n-- Definir la funci\u00f3n divideMedia por filtrado, comprensi\u00f3n y\r\n-- recursi\u00f3n. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La definici\u00f3n por filtrado es\r\ndivideMediaF :: [Double] -> ([Double],[Double])\r\ndivideMediaF xs = (filter (<m) xs, filter (>m) xs)\r\n    where m = media xs\r\n\r\n-- (media xs) es la media de xs. Por ejemplo,\r\n--    media [1,2,3]       ==  2.0\r\n--    media [1,-2,3.5,4]  ==  1.625 \r\n-- Nota: En la definici\u00f3n de media se usa la funci\u00f3n fromIntegral tal\r\n-- que (fromIntegral x) es el n\u00famero real correspondiente al n\u00famero\r\n-- entero x. \r\nmedia :: [Double] -> Double\r\nmedia xs = (sum xs) \/ fromIntegral (length xs)\r\n\r\n-- La definici\u00f3n por comprensi\u00f3n es\r\ndivideMediaC :: [Double] -> ([Double],[Double])\r\ndivideMediaC xs = ([x | x <- xs, x < m], [x | x <- xs, x > m])\r\n    where m = media xs\r\n\r\n-- La definici\u00f3n por recursi\u00f3n es\r\ndivideMediaR :: [Double] -> ([Double],[Double])\r\ndivideMediaR xs = divideMediaR' xs\r\n    where m = media xs\r\n          divideMediaR' [] = ([],[])\r\n          divideMediaR' (x:xs) | x < m  = (x:ys, zs)\r\n                               | x == m = (ys, zs)\r\n                               | x > m  = (ys, x:zs)\r\n                               where (ys, zs) = divideMediaR' xs\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.2. Comprobar con QuickCheck que las tres definiciones\r\n-- anteriores divideMediaF, divideMediaC y divideMediaR son\r\n-- equivalentes.\r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_divideMedia :: [Double] -> Bool\r\nprop_divideMedia xs =\r\n    divideMediaC xs == d &&\r\n    divideMediaR xs == d\r\n    where d = divideMediaF xs \r\n    \r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_divideMedia\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.3. Comprobar con QuickCheck que si (ys,zs) es el par\r\n-- obtenido aplic\u00e1ndole la funci\u00f3n divideMediaF a xs, entonces la suma\r\n-- de las longitudes de ys y zs es menor o igual que la longitud de xs.\r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_longitudDivideMedia :: [Double] -> Bool\r\nprop_longitudDivideMedia xs =\r\n    length ys + length zs <= length xs\r\n    where (ys,zs) = divideMediaF xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_longitudDivideMedia\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.4. Comprobar con QuickCheck que si (ys,zs) es el par\r\n-- obtenido aplic\u00e1ndole la funci\u00f3n divideMediaF a xs, entonces todos los\r\n-- elementos de ys son menores que todos los elementos de zs.\r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_divideMediaMenores :: [Double] -> Bool\r\nprop_divideMediaMenores xs =\r\n    and [y < z | y <- ys, z <- zs]\r\n    where (ys,zs) = divideMediaF xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_divideMediaMenores\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.5. Comprobar con QuickCheck que si (ys,zs) es el par\r\n-- obtenido aplic\u00e1ndole la funci\u00f3n divideMediaF a xs, entonces la\r\n-- media de xs no pertenece a ys ni a zs.\r\n-- Nota: Usar la funci\u00f3n notElem tal que (notElem x ys) se verifica si y\r\n-- no pertenece a ys.\r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_divideMediaSinMedia :: [Double] -> Bool\r\nprop_divideMediaSinMedia xs =\r\n    notElem m (ys ++ zs)\r\n    where  m       = media xs\r\n           (ys,zs) = divideMediaF xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_divideMediaSinMedia\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Funciones sobre cadenas                                            --\r\n-- ---------------------------------------------------------------------\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.1. Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    sumaDigitos :: String -> Int\r\n-- tal que (sumaDigitos xs) es la suma de los d\u00edgitos de la cadena\r\n-- xs. Por ejemplo, \r\n--    sumaDigitos \"SE 2431 X\"  ==  10\r\n-- Nota: Usar las funciones isDigit y digitToInt.\r\n-- ---------------------------------------------------------------------\r\n\r\nsumaDigitos :: String -> Int\r\nsumaDigitos xs = sum [digitToInt x | x <- xs, isDigit x]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    sumaDigitosRec :: String -> Int\r\n-- tal que (sumaDigitosRec xs) es la suma de los d\u00edgitos de la cadena\r\n-- xs. Por ejemplo, \r\n--    sumaDigitosRec \"SE 2431 X\"  ==  10\r\n-- Nota: Usar las funciones isDigit y digitToInt.\r\n-- ---------------------------------------------------------------------\r\n\r\nsumaDigitosRec :: String -> Int\r\nsumaDigitosRec [] = 0\r\nsumaDigitosRec (x:xs) \r\n    | isDigit x  = digitToInt x + sumaDigitosRec xs\r\n    | otherwise  = sumaDigitosRec xs\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 2.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_sumaDigitos :: String -> Bool\r\nprop_sumaDigitos xs = \r\n    sumaDigitos xs == sumaDigitosRec xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_sumaDigitos\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 3.1. Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    mayusculaInicial :: String -> String\r\n-- tal que (mayusculaInicial xs) es la palabra xs con la letra inicial\r\n-- en may\u00fascula y las restantes en min\u00fasculas. Por ejemplo, \r\n--    mayusculaInicial \"sEviLLa\"  ==  \"Sevilla\"\r\n-- Nota: Usar las funciones toLower y toUpper.\r\n-- ---------------------------------------------------------------------\r\n\r\nmayusculaInicial :: String -> String\r\nmayusculaInicial []     = []\r\nmayusculaInicial (x:xs) = toUpper x : [toLower x | x <- xs]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 3.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    mayusculaInicialRec :: String -> String\r\n-- tal que (mayusculaInicialRec xs) es la palabra xs con la letra\r\n-- inicial en may\u00fascula y las restantes en min\u00fasculas. Por ejemplo,\r\n--    mayusculaInicialRec \"sEviLLa\"  ==  \"Sevilla\"\r\n-- ---------------------------------------------------------------------\r\n\r\nmayusculaInicialRec :: String -> String\r\nmayusculaInicialRec [] = []\r\nmayusculaInicialRec (x:xs) = toUpper x : aux xs\r\n    where aux (x:xs) = toLower x : aux xs\r\n          aux []     = []\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 3.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_mayusculaInicial :: String -> Bool\r\nprop_mayusculaInicial xs = \r\n    mayusculaInicial xs == mayusculaInicialRec xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_mayusculaInicial\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 4.1. Se consideran las siguientes reglas de may\u00fasculas\r\n-- iniciales para los t\u00edtulos: \r\n--    * la primera palabra comienza en may\u00fascula y\r\n--    * todas las palabras que tienen 4 letras como m\u00ednimo empiezan\r\n--      con may\u00fasculas\r\n-- Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    titulo :: [String] -> [String]\r\n-- tal que (titulo ps) es la lista de las palabras de ps con\r\n-- las reglas de may\u00fasculas iniciales de los t\u00edtulos. Por ejemplo,\r\n--    *Main> titulo [\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion\"]\r\n--    [\"El\",\"Arte\",\"de\",\"la\",\"Programacion\"]\r\n-- ---------------------------------------------------------------------\r\n\r\ntitulo :: [String] -> [String]\r\ntitulo []     = []\r\ntitulo (p:ps) = mayusculaInicial p : [transforma p | p <- ps]\r\n\r\n-- (transforma p) es la palabra p con may\u00fascula inicial si su longitud\r\n-- es mayor o igual que 4 y es p en min\u00fascula en caso contrario\r\ntransforma :: String -> String\r\ntransforma p | length p >= 4 = mayusculaInicial p\r\n             | otherwise     = minuscula p\r\n\r\n-- (minuscula xs) es la palabra xs en min\u00fascula.\r\nminuscula :: String -> String\r\nminuscula xs = [toLower x | x <- xs]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 4.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    tituloRec :: [String] -> [String]\r\n-- tal que (tituloRec ps) es la lista de las palabras de ps con\r\n-- las reglas de may\u00fasculas iniciales de los t\u00edtulos. Por ejemplo,\r\n--    *Main> tituloRec [\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion\"]\r\n--    [\"El\",\"Arte\",\"de\",\"la\",\"Programacion\"]\r\n-- ---------------------------------------------------------------------\r\n\r\ntituloRec :: [String] -> [String]\r\ntituloRec []     = []\r\ntituloRec (p:ps) = mayusculaInicial p : tituloRecAux ps\r\n    where tituloRecAux []     = []\r\n          tituloRecAux (p:ps) = transforma p : tituloRecAux ps\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 4.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_titulo :: [String] -> Bool\r\nprop_titulo xs = titulo xs == tituloRec xs\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_titulo\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 5.1. Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    buscaCrucigrama :: Char -> Int -> Int -> [String] -> [String]\r\n-- tal que (buscaCrucigrama l pos lon ps) es la lista de las palabras de\r\n-- la lista de palabras ps que tienen longitud lon y poseen la letra l en\r\n-- la posici\u00f3n pos (comenzando en 0). Por ejemplo,\r\n--    *Main> buscaCrucigrama 'c' 1 7 [\"ocaso\", \"casa\", \"ocupado\"]\r\n--    [\"ocupado\"]\r\n-- ---------------------------------------------------------------------\r\n\r\nbuscaCrucigrama :: Char -> Int -> Int -> [String] -> [String]\r\nbuscaCrucigrama l pos lon ps =\r\n    [p | p <- ps,  \r\n         length p == lon, \r\n         0 <= pos,  pos < length p, \r\n         p !! pos == l]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 5.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    buscaCrucigramaRec :: Char -> Int -> Int -> [String] -> [String]\r\n-- tal que (buscaCrucigramaRec l pos lon ps) es la lista de las palabras\r\n-- de la lista de palabras ps que tienn longitud lon y posen la letra l\r\n-- en la posici\u00f3n pos (comenzando en 0). Por ejemplo,\r\n--    *Main> buscaCrucigramaRec 'c' 1 7 [\"ocaso\", \"acabado\", \"ocupado\"]\r\n--    [\"acabado\",\"ocupado\"]\r\n-- ---------------------------------------------------------------------\r\n\r\nbuscaCrucigramaRec :: Char -> Int -> Int -> [String] -> [String]\r\nbuscaCrucigramaRec letra pos lon [] = []\r\nbuscaCrucigramaRec letra pos lon (p:ps) \r\n    | length p == lon && 0 <= pos &#038;&#038; pos < length p &#038;&#038; p !! pos == letra \r\n        = p : buscaCrucigramaRec letra pos lon ps\r\n    | otherwise \r\n        = buscaCrucigramaRec letra pos lon ps\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 5.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_buscaCrucigrama :: Char -> Int -> Int -> [String] -> Bool\r\nprop_buscaCrucigrama letra pos lon ps =\r\n    buscaCrucigrama letra pos lon ps == buscaCrucigramaRec letra pos lon ps\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_buscaCrucigrama\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 6.1. Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    posiciones :: String -> Char -> [Int]\r\n-- tal que (posiciones xs y) es la lista de la posiciones del car\u00e1cter y\r\n-- en la cadena xs. Por ejemplo,\r\n--    posiciones \"Salamamca\" 'a'  ==  [1,3,5,8]\r\n-- ---------------------------------------------------------------------\r\n\r\nposiciones :: String -> Char -> [Int]\r\nposiciones xs y = [n | (x,n) <- zip xs [0..], x == y]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 6.2. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    posicionesRec :: String -> Char -> [Int]\r\n-- tal que (posicionesRec xs y) es la lista de la posiciones del\r\n-- car\u00e1cter y en la cadena xs. Por ejemplo,\r\n--    posicionesRec \"Salamamca\" 'a'  ==  [1,3,5,8]\r\n-- ---------------------------------------------------------------------\r\n\r\nposicionesRec :: String -> Char -> [Int]\r\nposicionesRec xs y = posicionesAux xs y 0\r\n    where\r\n      posicionesAux [] y n = []\r\n      posicionesAux (x:xs) y n | x == y    = n : posicionesAux xs y (n+1)\r\n                               | otherwise = posicionesAux xs y (n+1)\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 6.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_posiciones :: String -> Char -> Bool\r\nprop_posiciones xs y = \r\n    posiciones xs y == posicionesRec xs y\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_posiciones\r\n--    +++ OK, passed 100 tests.\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 7.1. Definir, por recursi\u00f3n, la funci\u00f3n\r\n--    contieneRec :: String -> String -> Bool\r\n-- tal que (contieneRec xs ys) se verifica si ys es una subcadena de\r\n-- xs. Por ejemplo, \r\n--    contieneRec \"escasamente\" \"casa\"   ==  True\r\n--    contieneRec \"escasamente\" \"cante\"  ==  False\r\n--    contieneRec \"\" \"\"                  ==  True\r\n-- Nota: Se puede usar la predefinida (isPrefixOf ys xs) que se verifica\r\n-- si ys es un prefijo de xs.\r\n-- ---------------------------------------------------------------------\r\n\r\ncontieneRec :: String -> String -> Bool\r\ncontieneRec _ []  = True       \r\ncontieneRec [] ys = False\r\ncontieneRec xs ys = isPrefixOf ys xs || contieneRec (tail xs) ys\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 7.2. Definir, por comprensi\u00f3n, la funci\u00f3n\r\n--    contiene :: String -> String -> Bool\r\n-- tal que (contiene xs ys) se verifica si ys es una subcadena de\r\n-- xs. Por ejemplo, \r\n--    contiene \"escasamente\" \"casa\"      ==  True\r\n--    contiene \"escasamente\" \"cante\"     ==  False\r\n--    contiene \"casado y casada\" \"casa\"  ==  True\r\n--    contiene \"\" \"\"                     ==  True\r\n-- Nota: Se puede usar la predefinida (isPrefixOf ys xs) que se verifica\r\n-- si ys es un prefijo de xs.\r\n-- ---------------------------------------------------------------------\r\n\r\ncontiene :: String -> String -> Bool\r\ncontiene xs ys = sufijosComenzandoCon xs ys \/= []\r\n\r\n-- (sufijosComenzandoCon xs ys) es la lista de los sufijos de xs que\r\n-- comienzan con ys. Por ejemplo,\r\n--    sufijosComenzandoCon \"abacbad\" \"ba\"  ==  [\"bacbad\",\"bad\"]\r\nsufijosComenzandoCon :: String -> String -> [String]\r\nsufijosComenzandoCon xs ys = [x | x <- sufijos xs, isPrefixOf ys x]\r\n\r\n-- (sufijos xs) es la lista de sufijos de xs. Por ejemplo,\r\n--    sufijos \"abc\"  ==  [\"abc\",\"bc\",\"c\",\"\"]\r\nsufijos :: String -> [String]\r\nsufijos xs = [drop i xs | i <- [0..length xs]]\r\n\r\n-- ---------------------------------------------------------------------\r\n-- Ejercicio 7.3. Comprobar con QuickCheck que ambas definiciones son\r\n-- equivalentes. \r\n-- ---------------------------------------------------------------------\r\n\r\n-- La propiedad es\r\nprop_contiene :: String -> String -> Bool\r\nprop_contiene xs ys = \r\n    contieneRec xs ys == contiene xs ys\r\n\r\n-- La comprobaci\u00f3n es\r\n--    *Main> quickCheck prop_contiene\r\n--    +++ OK, passed 100 tests.\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>La clase de hoy de Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas hemos comentando las soluciones de ejercicios de las dos primeras partes de la 9\u00aa relaci\u00f3n. La 1\u00aa parte contiene ejercicios con definiciones por comprensi\u00f3n y recursi\u00f3n. En concreto, se estudian funciones para calcular la compra de una persona agarrada y la divisi\u00f3n de&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[186],"tags":[295],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/1752"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=1752"}],"version-history":[{"count":2,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/1752\/revisions"}],"predecessor-version":[{"id":2891,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/1752\/revisions\/2891"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=1752"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=1752"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=1752"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}