{- Problema abordează definirea și manipularea unor arbori binari degenerați, pentru care un nod are cel mult un copil (stâng sau drept). Arborii au drept chei numere întregi, iar rădăcina este implicită (nu contează cheia acesteia). Un exemplu de astfel de arbore este ilustrat mai jos: * / 1 \ 2 / 3 / 4 \ 5 -} import Prelude hiding (Either, Left, Right) {- Tip de date cu etichete pentru tipul de nod (stâng sau drept). -} data Direction = Left | Right deriving (Show, Eq, Ord) {- 1a. (3p) Definiți tipul de date reprezentând un astfel de arbore binar degenerat. Țineți cont de caracteristica menționată pentru a produce o codificare compactă. -} data DegenTree = DT [(Direction, Int)] {- 1b. (1p) Definiți arborele din exemplu în reprezentarea voastră. -} degenTree = DT [(Left, 1), (Right, 2), (Left, 3), (Left, 4), (Right, 5)] {- 1c. (6p) Instanțiați clasa Show cu tipul DegenTree, pentru a produce o reprezentare în forma unui șir de caractere ca cea de mai jos pentru arborele exemplu: 1. .2 3. 4. .5 -} instance Show DegenTree where show (DT pairs) = foldr (\row acc -> row ++ "\n" ++ acc) "" $ map pairToRow pairs where pairToRow (direction, n) = case direction of Left -> s ++ "." Right -> "." ++ s where s = show n {- 2. (10p) Definiți funcția countSwitches, care calculează numărul de comutări de direcție (de la Left la Right sau invers), mergând dinspre rădăcină înspre frunză. Pentru arborele exemplu, rezultatul este 3 (între cheile 1-2, 2-3, 4-5). -} countSwitches :: DegenTree -> Int countSwitches (DT pairs) = length $ filter id $ zipWith (\(d1, _) (d2, _) -> d1 /= d2) pairs (tail pairs) {- 3. (10p) Definiți funcția chainLengths, care întoarce lista lungimilor lanțurilor cu direcții identice consecutive (numai Left sau numai Right), mergând dinspre rădăcină înspre frunză. Pentru arborele exemplu, rezultatul este [1, 1, 2, 1], întrucât: * nodul 1 formează un lanț de lungime 1 spre stânga; * nodul 2 formează un lanț de lungime 1 spre dreapta; * nodurile 3-4 formează un lanț de lungime 2 spre stânga; * nodul 5 formează un lanț de lungime 1 spre dreapta. -} chainLengths :: DegenTree -> [Int] chainLengths (DT pairs) = lastCrt : lst where consecutivePairs = zipWith (\(d1, _) (d2, _) -> d1 == d2) pairs (tail pairs) (lastCrt, lst) = foldr (\b (crt, lst) -> if b then (crt + 1, lst) else (1, crt : lst)) (1, []) consecutivePairs {- Barem: 1a Pot reprezenta tipul cum vor, fie care listă de perechi, ca mai sus, fie care tip de date explicit recursiv. Etichetele Left și Right pot însoți fie copilul, ca mai sus, fie părintele, spunând că pe stânga sau dreapta va fi copilul nodului curent. De exemplu, e ok și o reprezentare de forma: data DegenTree = NodeWithLeftChild Int DegenTree | NodeWithRightChild Int DegenTree 1p: Prezența informației de cheie (Int) 1p: Prezența informației de direcție a unui copil (fie folosind tipul Direction, fie codificând altfel, vezi NodeWithLeftChild etc.) 1p: Reprezentarea secvenței (ca listă sau recursivitate explicită) 1b 1p: reprezentarea corectă a arborelui exemplu 1c 1p: reprezentarea corectă a unui nod stâng (x.) 1p: reprezentarea corectă a unui nod drept (.x) 2p: parcurgerea întregului arbore 2p: adăugarea de linie nouă între reprezentările a două nouri 2 4p: identificarea unei schimbări de direcție 3p: numărarea unei schimbări de direcție 3p: numărarea tuturor schimbărilor de direcție 3 3p: identificarea păstrării direcției 3p: incrementarea lungimii lanțului curent la păstrarea direcției 3p: adăugarea lungimii lanțului curent la listă la schimbarea direcției 1p: reinițializarea lungimii lanțului curent la schimbarea direcției -}