Representaciones de matrices
Las matrices se pueden representar de distintas formas. Por ejemplo, la matriz
|7 5 6| |1 9 4|
se puede representar como la terna
([7,5,6,1,9,4],2,3)
(donde la primera componente es la lista de los elementos de matriz, la segunda es su número de filas y la tercera es su número de columnas) y también se puede representar como una lista de listas
[[[7,5,6],[1,9,4]]
(donde cada elemento es una de las filas de la matriz).
Definir las funciones
ternaAlistas :: ([a],Int,Int) -> [[a]] listasAterna :: [[a]] -> ([a],Int,Int)
tales que ternaAlistas pase de la primera representación a la segunda y listasAterna pase de la segunda a la primera. Por ejemplo,
ternaAlistas ([7,5,6,1,9,4],2,3) == [[7,5,6],[1,9,4]] listasAterna [[7,5,6],[1,9,4]] == ([7,5,6,1,9,4],2,3) ternaAlistas ([7,5,6,1,9,4],3,2) == [[7,5],[6,1],[9,4]] listasAterna [[7,5],[6,1],[9,4]] == ([7,5,6,1,9,4],3,2)
Soluciones
import Data.List.Split (chunksOf) import Control.Applicative (liftA3) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª definición de ternaAlistas -- ============================= ternaAlistas1 :: ([a],Int,Int) -> [[a]] ternaAlistas1 (xs,_,m) = segmentos m xs -- (segmentos m xs) es la lista de los segmentos de xs formados por m -- elementos. Por ejemplo, -- segmentos 3 [7,5,6,1,9,4] == [[7,5,6],[1,9,4]] -- segmentos 2 [7,5,6,1,9,4] == [[7,5],[6,1],[9,4]] segmentos :: Int -> [a] -> [[a]] segmentos _ [] = [] segmentos m xs = take m xs : segmentos m (drop m xs) -- 2ª definición de ternaAlistas -- ============================= ternaAlistas2 :: ([a],Int,Int) -> [[a]] ternaAlistas2 (xs,_,m) = chunksOf m xs -- 1ª definición de listasAterna -- ============================= listasAterna1 :: [[a]] -> ([a],Int,Int) listasAterna1 xss = (concat xss, length xss, length (head xss)) -- 2ª definición de listasAterna -- ============================= listasAterna2 :: [[a]] -> ([a], Int, Int) listasAterna2 = liftA3 (,,) concat length (length . head) -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG1 :: (([Int], Int, Int) -> [[Int]]) -> Spec specG1 ternaAlistas = do it "e1" $ ternaAlistas ([7,5,6,1,9,4],2,3) `shouldBe` [[7,5,6],[1,9,4]] it "e2" $ ternaAlistas ([7,5,6,1,9,4],3,2) `shouldBe` [[7,5],[6,1],[9,4]] specG2 :: ([[Int]] -> ([Int],Int,Int)) -> Spec specG2 listasAterna = do it "e1" $ listasAterna [[7,5,6],[1,9,4]] `shouldBe` ([7,5,6,1,9,4],2,3) it "e2" $ listasAterna [[7,5],[6,1],[9,4]] `shouldBe` ([7,5,6,1,9,4],3,2) spec :: Spec spec = do describe "def. 1" $ specG1 ternaAlistas1 describe "def. 2" $ specG1 ternaAlistas2 describe "def. 1" $ specG2 listasAterna1 describe "def. 2" $ specG2 listasAterna2 -- La verificación es -- λ> verifica -- 8 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- Generador de ternas. Por ejemplo, -- λ> generate genTerna -- ([14,-7,27,-25,30,0,18,7],2,4) -- λ> generate genTerna -- ([19,-11,-3,-18,23],5,1) genTerna :: Gen ([Int], Int, Int) genTerna = do n <- choose (1, 5) m <- choose (1, 5) xs <- vector (n * m) return (xs, n, m) -- La propiedad es prop_equiv_ternaAlistas :: Property prop_equiv_ternaAlistas = forAll genTerna $ \t -> ternaAlistas1 t == ternaAlistas2 t -- La comprobación es -- λ> quickCheck prop_equiv_ternaAlistas -- +++ OK, passed 100 tests. -- genListas es un generador de lista de listas todas de la misma -- longitud. Por ejemplo, -- λ> generate genListas -- [[0,-3,6],[14,20,-19,-21,25]] -- λ> generate genListas -- [[21,3,-19],[-14],[-4,-19,20,23],[-13,-2,-23,-10,28]] genListas :: Gen [[Int]] genListas = do n <- choose (1, 5) vectorOf n $ do m <- choose (1, 5) vectorOf m arbitrary -- La propiedad es prop_equiv_listasAterna :: Property prop_equiv_listasAterna = forAll genListas $ \xss -> listasAterna1 xss == listasAterna2 xss -- La comprobación es -- λ> quickCheck prop_equiv_listasAterna -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> length (ternaAlistas1 ([1..10^4*10^4],10^4,10^4)) -- 10000 -- (1.63 secs, 7,203,081,632 bytes) -- λ> length (ternaAlistas2 ([1..10^4*10^4],10^4,10^4)) -- 10000 -- (1.59 secs, 7,202,361,648 bytes) -- λ> ejemplo = replicate (10^4) (replicate (10^4) 0) -- λ> listasAterna1 ejemplo == listasAterna1 ejemplo -- True -- (1.99 secs, 11,203,482,192 bytes) -- λ> listasAterna2 ejemplo == listasAterna2 ejemplo -- True -- (2.04 secs, 11,203,482,248 bytes)