Difference between revisions of "FP Laboratory 11/cs"
Jump to navigation
Jump to search
(Created page with "Naše '''onClick''' je funkce, která se spustí po kliknutí na tlačítko. Parametrem této funkce jsou data popisující událost, která se osluhu spustila.") |
(Updating to match new version of source page) |
||
(13 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | == | + | == Složitá datová struktura == |
− | + | Uvažujme následující datovou strukturu reprezentující nějaký druh grafického uživatelského rozhraní. | |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 13: | Line 13: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Jako příklad můžeme použít následující datovou strukturu. | |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
gui :: Component | gui :: Component | ||
gui = | gui = | ||
− | Container | + | Container "My App" |
− | + | [ Container "Menu" | |
− | [ Container | ||
− | |||
[ Button "btn_new" (Position (Point 0 0) 100 20) "New", | [ Button "btn_new" (Position (Point 0 0) 100 20) "New", | ||
Button "btn_open" (Position (Point 100 0) 100 20) "Open", | Button "btn_open" (Position (Point 100 0) 100 20) "Open", | ||
Line 93: | Line 91: | ||
| otherwise = Container cName [insertInto c toName element |c<-children] | | otherwise = Container cName [insertInto c toName element |c<-children] | ||
insertInto x toName element = x | insertInto x toName element = x | ||
+ | </syntaxhighlight> | ||
+ | </div> | ||
+ | <div style="clear:both"></div> | ||
+ | |||
+ | <div class="mw-translate-fuzzy"> | ||
+ | * Vytvořte funkci <code>deleteFrom</code>, která odstraní prvek ze stávajícího kontejneru z GUI. Parametry funkcí budou: | ||
+ | ** prvním parametrem bude GUI, kde odstraňujeme prvek; | ||
+ | ** druhý parametr je název komponenty, která bude odstraněna, můžete bezpečně předpokládat, že bude vždy existovat; | ||
+ | </div> | ||
+ | |||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | deleteFrom :: Component -> String -> Component | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark"> | ||
+ | ghci> deleteFrom gui "btn_close" | ||
+ | Container - My App | ||
+ | Container - Menu | ||
+ | (0,0)[100,20] Button[btn_new]: New | ||
+ | (100,0)[100,20] Button[btn_open]: Open | ||
+ | Container - Body | ||
+ | (0,20)[300,500] TextBox[textbox_1]: Some text goes here | ||
+ | Container - Footer | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution"> | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | deleteFrom :: Component -> String -> Component | ||
+ | deleteFrom (Container x child) target = Container x [deleteFrom c target |c<-child, name c /=target ] | ||
+ | deleteFrom c _ = c | ||
</syntaxhighlight> | </syntaxhighlight> | ||
</div> | </div> | ||
Line 115: | Line 143: | ||
... | ... | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvořte funkci <code>clickOnButton</code>, která dostane naše GUI a nějakou událost. Pokud je parametrem instance <code>MouseEvent</code> a pozice, na kterou jsme klikli, je uvnitř některého z tlačítek GUI, pak vyhodnotí odpovídající funkci <code>onClick</code> a výsledkem bude získáný řetězec. Ve všech ostatních případech bude výsledkem <code>Nothing</code>. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 149: | Line 177: | ||
<div style="clear:both"></div> | <div style="clear:both"></div> | ||
− | == | + | == Doplňková cvičení == |
− | * | + | * Uvažujme následující definici a příklad m-árního stromu. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 162: | Line 190: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvořte funkci, která sečte všechny hodnoty uložené ve stromu m-ary. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 168: | Line 196: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvořte funkci, která extrahuje všechny hodnoty z m-arního strimu do seznamu. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 174: | Line 202: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvořte funkci, která spočítá všechny listy v m-arním stromu. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
mLeafCount :: MTree a -> Int | mLeafCount :: MTree a -> Int | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvořte funkci, která najde maximální hodnotu uloženou v m-árním stromu. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 185: | Line 213: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvoření funkce, která zkontroluje, zda je daný prvek uložen v m-árním |
+ | stromu. | ||
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
Line 191: | Line 220: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * | + | * Vytvoření funkce, která vrátí počet prvků větších než zadaná hodnota. |
<syntaxhighlight lang="Haskell"> | <syntaxhighlight lang="Haskell"> | ||
mGreaterThan :: Ord a => MTree a -> a -> Int | mGreaterThan :: Ord a => MTree a -> a -> Int | ||
</syntaxhighlight> | </syntaxhighlight> |
Latest revision as of 11:41, 19 November 2024
Složitá datová struktura
Uvažujme následující datovou strukturu reprezentující nějaký druh grafického uživatelského rozhraní.
data Point = Point {column::Int,row::Int} deriving (Show)
data Position = Position {leftTopCorner :: Point, width :: Int, height :: Int}
data Component
= TextBox {name :: String, position :: Position, text :: String}
| Button {name :: String, position :: Position, text :: String}
| Container {name :: String, children :: [Component]}
Jako příklad můžeme použít následující datovou strukturu.
gui :: Component
gui =
Container "My App"
[ Container "Menu"
[ Button "btn_new" (Position (Point 0 0) 100 20) "New",
Button "btn_open" (Position (Point 100 0) 100 20) "Open",
Button "btn_close" (Position (Point 200 0) 100 20) "Close"
],
Container "Body" [TextBox "textbox_1" (Position (Point 0 20) 300 500) "Some text goes here"],
Container "Footer" []
]
- Přidejte typ
Component
do typove třídyShow
.
Výsledek pro naše data z předchozího příkladu by měl vypadat takto.
ghci> gui
Container - My App
Container - Menu
(0,0)[100,20] Button[btn_new]: New
(100,0)[100,20] Button[btn_open]: Open
(200,0)[100,20] Button[btn_close]: Close
Container - Body
(0,20)[300,500] TextBox[textbox_1]: Some text goes here
Container - Footer
instance Show Position where
show (Position (Point col row) width height) = "(" ++ show col ++ "," ++ show row ++ ")["++ show width++","++ show height++"]"
instance Show Component where
show :: Component -> String
show gui = showIndent "" gui where
showIndent ind (TextBox name position text) = ind ++ show position ++ " TextBox[" ++ name ++ "]: " ++ text ++"\n"
showIndent ind (Button name position text) = ind ++ show position ++ " Button[" ++ name ++ "]: " ++ text ++"\n"
showIndent ind (Container name children) = let
inner = concat[showIndent (ind++"\t") c |c<-children]
in ind ++ "Container - " ++ name ++ "\n" ++ inner
- Vytvořte funkci
insertInto
, která vloží prvek do existujícího kontejneru z GUI. Parametry funkce budou:- prvním parametrem bude GUI, do kterého budeme vkládat nový prvek;
- druhým parametrem bude název kontejneru, do kterého vkládáme nový prvek, lze bezpečně předpokládat, že bude vždy existovat. Prvek bude v kontejneru umístěn jako poslední;
- posledním parametrem je vložený prvek.
insertInto :: Component -> String -> Component -> Component
ghci> insertInto gui "Footer" (TextBox "Done" (Position (Point 0 500) 300 10) "We are done!")
Container - My App
Container - Menu
(0,0)[100,20] Button[btn_new]: New
(100,0)[100,20] Button[btn_open]: Open
(200,0)[100,20] Button[btn_close]: Close
Container - Body
(0,20)[300,500] TextBox[textbox_1]: Some text goes here
Container - Footer
(0,500)[300,10] TextBox[Done]: We are done!
insertInto :: Component -> String -> Component -> Component
insertInto (Container cName children ) toName element
| cName == toName = Container cName (children++[element])
| otherwise = Container cName [insertInto c toName element |c<-children]
insertInto x toName element = x
- Vytvořte funkci
deleteFrom
, která odstraní prvek ze stávajícího kontejneru z GUI. Parametry funkcí budou:- prvním parametrem bude GUI, kde odstraňujeme prvek;
- druhý parametr je název komponenty, která bude odstraněna, můžete bezpečně předpokládat, že bude vždy existovat;
deleteFrom :: Component -> String -> Component
ghci> deleteFrom gui "btn_close"
Container - My App
Container - Menu
(0,0)[100,20] Button[btn_new]: New
(100,0)[100,20] Button[btn_open]: Open
Container - Body
(0,20)[300,500] TextBox[textbox_1]: Some text goes here
Container - Footer
deleteFrom :: Component -> String -> Component
deleteFrom (Container x child) target = Container x [deleteFrom c target |c<-child, name c /=target ]
deleteFrom c _ = c
- Rozšiřte definici tlačítka v našem GUI takto.
data Event = MouseEvent Point
| KeyEvent {keyPressed::Char} deriving (Show)
...
| Button {name :: String, position :: Position, text :: String, onClick :: Maybe (Event -> String)}
...
Naše onClick je funkce, která se spustí po kliknutí na tlačítko. Parametrem této funkce jsou data popisující událost, která se osluhu spustila.
...
[ Button "btn_new" (Position (Point 0 0) 100 20) "New" (Just (\event -> "Clicked on new button.")),
Button "btn_open" (Position (Point 100 0) 100 20) "Open" Nothing,
Button "btn_close" (Position (Point 200 0) 100 20) "Close" (Just (\event -> "Clicked on close button.")) ]
...
- Vytvořte funkci
clickOnButton
, která dostane naše GUI a nějakou událost. Pokud je parametrem instanceMouseEvent
a pozice, na kterou jsme klikli, je uvnitř některého z tlačítek GUI, pak vyhodnotí odpovídající funkcionClick
a výsledkem bude získáný řetězec. Ve všech ostatních případech bude výsledkemNothing
.
clickOnButton :: Component -> Event -> Maybe String
ghci> clickOnButton gui (MouseEvent (Point 5 5))
Just "Clicked on new button."
ghci> clickOnButton gui (MouseEvent (Point 205 5))
Just "Clicked on close button."
ghci> clickOnButton gui (MouseEvent (Point 205 50))
Nothing
isInside :: Point -> Position -> Bool
isInside (Point pCol pRow) (Position (Point cornerCol cornerRow) width height) =
cornerCol <= pCol && pCol <= cornerCol + width && cornerRow <= pRow && pRow <= cornerRow + height
getFirstOrNothing :: [Maybe a] -> Maybe a
getFirstOrNothing [] = Nothing
getFirstOrNothing (Nothing:xs) = getFirstOrNothing xs
getFirstOrNothing (Just x: xs) = Just x
clickOnButton :: Component -> Event -> Maybe String
clickOnButton (Button {position = pos, onClick = (Just func)}) (MouseEvent point) | isInside point pos = Just (func (MouseEvent point))
clickOnButton (Container {children=inner}) event = getFirstOrNothing [clickOnButton c event |c<-inner]
clickOnButton _ _ = Nothing
Doplňková cvičení
- Uvažujme následující definici a příklad m-árního stromu.
data MTree a = MTree a [MTree a]
testTree1 :: MTree Int
testTree1 = MTree 1 [(MTree 2 [(MTree 3 []),(MTree 4 [(MTree 5 []),(MTree 6 [])]), (MTree 7 []),(MTree 8 [])]), (MTree 9 [])]
- Vytvořte funkci, která sečte všechny hodnoty uložené ve stromu m-ary.
msum :: MTree Int -> Int
- Vytvořte funkci, která extrahuje všechny hodnoty z m-arního strimu do seznamu.
mToList :: MTree a -> [a]
- Vytvořte funkci, která spočítá všechny listy v m-arním stromu.
mLeafCount :: MTree a -> Int
- Vytvořte funkci, která najde maximální hodnotu uloženou v m-árním stromu.
mMaxTree :: Ord a => MTree a -> a
- Vytvoření funkce, která zkontroluje, zda je daný prvek uložen v m-árním
stromu.
mContains :: Eq a => MTree a -> a -> Bool
- Vytvoření funkce, která vrátí počet prvků větších než zadaná hodnota.
mGreaterThan :: Ord a => MTree a -> a -> Int