Hogyan lehetne javítani ezeket a haskell compress és decompress függvényeket?
Adjuk meg azt a függvényt, amely egy listát úgy tömörít, hogy az egymás után szereplő azonos elemeket darabszám-elem párokká alakítja. Hasznos lehet a group függvény.
import Data.List
compress :: (Eq a, Integral b) => [a] -> [(b, a)]
compress l = zip ( length $ group l) ( head $ group l)
Példák:
compress "aaaabccaadeeee" == [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
compress "oh hello!!" == [(1,'o'),(1,'h'),(1,' '),(1,'h'),(1,'e'),(2,'l'),(1,'o'),(2,'!')]
compress [] == []
compress [1,1,0,0,0,1,1,1] == [(2,1),(3,0),(3,1)]
Adjuk meg azt a függvényt, amely egy tömörített listából visszaállítja az eredetit. Hasznos lehet a replicate függvény.
decompress :: (Eq a, Integral b) => [(b, a)] -> [a]
decompress l = concat [replicate (fst x) (snd x) | x <- l]
Példák:
decompress [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')] == "aaaabccaadeeee"
decompress [(1,'o'),(1,'h'),(1,' '),(1,'h'),(1,'e'),(2,'l'),(1,'o'),(2,'!')] == "oh hello!!"
decompress [] == []
decompress [(2,1),(3,0),(3,1)] == [1,1,0,0,0,1,1,1]
Egy byte-ban tárolod el a darabszámot is és az értéket is.
Plusz, ugye, ha az MSB 1 akkor tomoritett, ha 0 akkor nem.
Ha MSB = 1 akkor a darabszám lehet max plusz egy, hiszen egynél tobb a darabszám, ha már egyszer tomoritve van.
01234567890123456
aaaaaaaaaaaaaaaaa
Ez egy byte-ban:
1 1110 001
a compress hibás
ha megnézed a zip típusát (:t zip), akkor látod, hogy az első paramétere "[a]" típusú (tehát valamilyen lista, mindegy, hogy mit tartalmaz, az "a" akár lehet szintén valamilyen lista típus is, de ez most lényegtelen)
te pedig egy Int típusú első paramétert adtál meg neki (:t length $ group l)
de ha ezt megpróbálod futtatni, akkor meg is kapod pontosan ezt a hibaüzenetet: "Couldn't match expected type `[a]' with actual type `Int'"
mindig azzal kell kezdeni, hogy mi a hibaüzenet, pontosan le van írva benne, hogy mi nem jó, de már nem egyszer javasoltam ezt szerintem..
ha az első példában megadott stringre futtatod a group függvényt, akkor ezt kapod: ["aaaa","b","cc","aa","d","eeee"]
mit kell ezzel csinálni? gyakorlatilag a lista minden tagjának meg kell feleltetni egy rendezett párt
az ilyen típusú leképezésekre van kitalálva a map függvényt
a decompressben szintén egy ilyen leképezést kell megcsinálni, csak a fordított irányban
a listás kifejezés helyett lehet használni map-et
tehát valahogy így nézne ki:
decompress = concat $ map ...
pl. az ilyen esetekben (amikor a concat és a map függvényeket egymás után kell használni) lehet használni a concatMap függvényt
egyébként meg teljesen felesleges kétszer ugyanazt a felbontást előállítani
pl. egy where-rel vagy let-in-nel ki lehet emelni egy tagot, amit többször is fel akarsz használni
pl.:
f :: [Char] -> [Char]
f x = (g ("akármi" ++ x)) ++ (h ("akármi" ++ x))
ehelyett
f :: [Char] -> [Char]
f x = (g y) ++ (h y) where y = ("akármi" ++ x)
vagy
f :: [Char] -> [Char]
f x = let y = ("akármi" ++ x) in (g y) ++ (h y)
module PointfreeStyle where
import Data.List (group, replicate)
import Control.Arrow ((&&&))
compress :: Eq a => [a] -> [(a, Int)]
compress = map (head &&& length) . group
decompress :: [(b, Int)] -> [b]
decompress = concatMap (uncurry $ flip replicate)
test, test1, test2, test3 :: Bool
test = test1 && test2 && test3
test1 = compress "Mississippi" == [('M', 1), ('i', 1), ('s', 2), ('i', 1), ('s', 2), ('i', 1), ('p', 2), ('i', 1)]
test2 = decompress [('M', 1), ('i', 1), ('s', 2), ('i', 1), ('s', 2), ('i', 1), ('p', 2), ('i', 1)] == "Mississippi"
test3 = (decompress . compress) "Mississippi" == "Mississippi"
Köszönöm szépen az inspirációt, kedves 3-as.
Megpróbáltam mindent besűríteni egy tömör modulba (ld. az előző válasz).
Tudom, most túl tömör lett, de érdemes részenként megnézni.
A lényeg és a talán elsőre nehezen érthető rész az &&& művelet.
Bár az Arrow-elmélet kicsit elfedi a lényeget, mivel az egy tágabb általánosítás, de a lényeg az, hogy a &&& az az alábbi műveletnek felel meg:
(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
Given two functions, apply both to a single argument to form a pair. A specialised version of the Arrow &&&.
(succ &&& pred) 1 == (2,0)
Íme a dokumentációja:
Elérhető az alábbi modulból:
import Data.Tuple.Extra ((&&&))
ha esetleg nincs meg, lehet az Arrow modulból is importálni (ott is ugyanazt jelenti, csak egy általánosabb elmélet van mögötte, ami elsőre kicsit elfedi a lényeget, bár hosszú távon azt is mókás megismerni):
import Control.Arrow ((&&&))
Kedves Kérdező,
A Te `zip`-es elgondolásod is javítható, bár fogalmilag kissé kevésbé ökonomikus, és talán erőforrás-igényesebb:
-------------------------------
module ZipSample where
import Data.List (group, replicate)
compress :: Eq a => [a] -> [(a, Int)]
compress l = zip (map head $ group l) (map length $ group l)
decompress :: [(b, Int)] -> [b]
decompress = concatMap (uncurry $ flip replicate)
test, test1, test2, test3 :: Bool
test = test1 && test2 && test3
test1 = compress "Mississippi" == [('M', 1), ('i', 1), ('s', 2), ('i', 1), ('s', 2), ('i', 1), ('p', 2), ('i', 1)]
test2 = decompress [('M', 1), ('i', 1), ('s', 2), ('i', 1), ('s', 2), ('i', 1), ('p', 2), ('i', 1)] == "Mississippi"
test3 = (decompress . compress) "Mississippi" == "Mississippi"
--------------------------
Látható, hogy a `&&&`-es megoldás a `zip`-es megoldással szemben azt teszi lehetővé, hogy a két függvényágból a ,,közös'' `map` és `group` függvény kiemelhető legyen:
- a `group` az elágazás előtti osztatlan közös függvényágba,
- a `map` pedig bele magába az egyik fő architekturális konstrukcióba (`concatMap`).
Kapcsolódó kérdések:
Minden jog fenntartva © 2025, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!