Van haskellben egy rendezett karakterpárokat tartalmazó lista (konstans lista). Hogy írjak olyan függvényt, aminek ha paraméterül megadom a listám egyik rendezett párjának első elemét, akkor visszaadja a másikat? (tehát a hozzá tartozó karaktert)
A lookup függvény nem pont ezt csinálja?
lookup :: Eq a => a -> [(a, b)] -> Maybe b
Ha jól értem csak végig kell iterálnod rekurzívan a listán és minden elemet megvizsgálni, amíg meg nem találod a keresett elemet. Ha üres a lista akkor hibával térsz vissza miszerint nincs ilyen elem.
Pároknál hasznos lehet az fst és snd függvények amik a pár első és második elemét adják vissza.
Lényegében egy 10 perces feladat, csak későn láttam a kérdésedet :) A hoogle-t és a zvon.org oldalát ajánlom használni, illetve az ELTE-s funkcprog oldalát.
De itt a megoldás (viszonylag sok megjegyzéssel együtt lett 14 sor):
import Data.Maybe
--1 feladat--
table :: [(Char, Char)]
table = zip "abcdefghijklmnopqrstuvwxyz " "defghijklmnopqrstuvwxyzabc "
--2 feladat--
-- Megjegyzés Data.Maybe a fromJust függvény miatt kell!--
shift :: Char -> Char
shift x = fromJust (lookup x table)
--3 feladat--
encrypt :: String -> String
encrypt x = map shift x
Lehet előfordul elegánsabb megoldás is, de hirtelen összecsapva ennyiből úsztam meg a feladatot
Fontos része a feladatnak, hogy tkp. nincs pontosan specifikálva. Kell kezelni azt az esetet, hogy ha nincs meg a ,,keresőkulcs''.
Pontosítási, továbbspecifikációs lehetőségek:
1) Nem-totális (vagyis parciális) függvényt írunk, tehát ha nem talál egyezést a keresőkulcs alapján, akkor error "Hibaüzenet", esetleg undefined.
2) A definiálandó függvényünknek adunk egy plusz paramétert is, egy defaultÉrték paramétert. Ha nem talál egyezést a keresőkulcs alapján, akkor a defaultÉrtéket adja vissza.
3) Maybe-be csomagoljuk az eredményt, és ha nem talál egyezést a keresőkulcs alapján, akkor Nothing, ha meg van, akkor pedig Just találtérték.
Ezeket a továbbspecifikációs lehetőségeket ,,erejük sorrendjében'' írtam. Tehát a legáltalánosabb a 3) megoldás, abból akár az előző kettőt is könnyen fel lehet írni. A 2) megoldás nem olyan általános, mint a 3), de a 2)-ból is fel lehet írni az 1) megoldást. A legszűkebb az 1) megoldás, mert a 2) és a 3) megoldás tud kezelni olyan eseteket is, amilyeneket az 1) nem.
Megadom mindháromra a megvalósítást:
lookup1 :: Eq kulcs => [(kulcs, érték)] -> kulcs -> érték
lookup1 [] _ = error "A keresőkulcs szerinti egyezés nincs a keresési leképezésben!"
lookup1 ((kulcs, érték) : hozzárendelések) keresőkulcs = if kulcs == keresőkulcs then érték else lookup1 hozzárendelések keresőkulcs
lookup2 :: Eq kulcs => érték -> [(kulcs, érték)] -> kulcs -> érték
lookup2 defaultÉrték [] _ = defaultÉrték
lookup2 defaultÉrték ((kulcs, érték) : hozzárendelések) keresőkulcs = if kulcs == keresőkulcs then érték else lookup2 defaultÉrték hozzárendelések keresőkulcs
lookup3 :: Eq kulcs => [(kulcs, érték)] -> kulcs -> Maybe érték
lookup3 [] _ = Nothing
lookup3 ((kulcs, érték) : hozzárendelések) keresőkulcs = if keresőkulcs == kulcs then Just érték else lookup3 hozzárendelések keresőkulcs
Ha pl. megírjuk a legáltalánosabb, vagyis a lookup3 megoldást, akkor ebből már a lookup3 is könnyen definiálható úgy, ahogy az előző Válaszoló is utalt rá:
lookup1 hozzárendelések keresőkulcs
ugyanúgy viselkedik, mint a
fromJust (lookup3 hozzárendelések keresőkulcs)
és hasonlóképp, a lookup2 is előállítható a lookup3-ból: a
lookup2 defaultValue leképezések keresőkulcs
pedig ugyanúgy viselkedik, mint a
maybe defaultÉrték id (lookup3 leképezések keresőkulcs)
Látjuk tehát, hogy a lookup3 a leginformációgazdagabb.
Látszik az is, hogy a fromJust és a maybe azok ilyen hasznos kicsomagoló függvények a Maybe-re. Ilyen kis hasznos csomagoló- és kicsomagoló dolgok még sokszor lesznek, és ha sok ilyennel találkozik az ember, akkor sok érdekesség általánosítható belőlük, ebből majd eljuttok a monászok fogalmáig, amivel nagyon jó programszervezési stílust lehet meríteni: egészen nagy és összetett Haskell-projektek írhatók meg szép szervezett architektúra szerint, úgy hogy a forráskód mindig könnyen érthető és tesztelhető marad. A monászok fogalma legalább olyan érdekes és jó találmány a funkcionális programozásban, mint ahogy az objektumorientált programozásban az objektumok, interfészek és egyéb dolgok, amelyek szintén a forráskód szép architekturális felépítését teszik lehetővé, bár persze ott egészen más megközelítésben.
Majd a rekurzív adatszerkezeteknél pedig (főleg a listáknál) lesz ilyen fold (más néven reduce) féle ötlet is. Azzal szép tömör kóddal fel lehet dolgozni teljes listákat. Pl. egy számlista összege előállítható úgy, hogy
foldr (+) 0 számlista
Ez szép tömören azt fejezi ki, hogy az üres számlista összegét 0-nak tekintjük (és erről az értékről is indulunk az összegzés során), és minden egyes új elemnél pedig az addig meglévő összeghez hozzáadjuk az új elemet.
Akár a mostani feladatot is fel lehet írni ilyen módon:
lookup1' :: Eq kulcs => [(kulcs, érték)] -> kulcs -> érték
lookup1' hozzárendelések keresőkulcs = foldr (match12 keresőkulcs) (error "...") hozzárendelések
lookup2' :: Eq kulcs => érték -> [(kulcs, érték)] -> kulcs -> érték
lookup2' defaultÉrték hozzárendelések keresőkulcs = foldr (match12 keresőkulcs) defaultÉrték hozzárendelések
Ezekhez tartozik egy ,,közös'' match12 segédfüggvény:
match12 :: Eq kulcs => kulcs -> (kulcs, érték) -> érték -> érték
match12 keresőkulcs (kulcs, érték) továbbszámolás = if kulcs == keresőkulcs then érték else továbbszámolás
ez az előbbi sor tömörebben is írható, úgy is lehet írni, hogy:
match12 keresőkulcs (kulcs, érték) = if kulcs == keresőkulcs then const érték else id
-- A harmadik stílusú lookup is felírható:
lookup3' :: Eq kulcs => [(kulcs, érték)] -> kulcs -> Maybe érték
lookup3' hozzárendelések keresőkulcs = foldr (match3 keresőkulcs) Nothing hozzárendelések
őneki külön match-segédfüggvénye van:
match3 :: Eq kulcs => kulcs -> (kulcs, érték) -> Maybe érték -> Maybe érték
match3 keresőkulcs (kulcs, érték) továbbkeresés = if kulcs == keresőkulcs then Just érték else továbbkeresés
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, 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!