import Data.Char -- Exercitiul 1 -- a) data Reteta = Stop | R Ing Reteta deriving Show data Ing = Ing String Int deriving Show -- a) -- Returneaza cantitatea maxima a ingredientului cu numele "nume", case insensitive. -- Folosesc map toLower pentru a aplica functia "toLower" tuturor caracterelor dintr-un string. r15pmMaxIng :: Reteta -> String -> Int r15pmMaxIng Stop _ = 0 r15pmMaxIng (R (Ing nume_ing cantitate) r) nume = let maxRest = r15pmMaxIng r nume in if map toLower nume_ing == map toLower nume then max cantitate maxRest else maxRest -- Verifica daca reteta din primul parametru contine ingredientul din al doilea parametru. r15pmContine :: Reteta -> Ing -> Bool r15pmContine Stop _ = False r15pmContine (R ing r) toFind | ing == toFind = True | otherwise = r15pmContine r toFind -- Face tot ce face si r15pmEx1 dar mai are si parametru reteta_initiala. -- Aveam nevoie si de parametrul reteta_initiala pentru ca eu caut in reteta initiala cantitatea maxima a ingredientului curent. -- Nu e clar din enunt ce sa fac daca am ingrediente duplicate, asa ca le-am eliminat, afisand mereu ultima aparitie. -- Daca nu voiam sa le elimin, scoteam "&& not (r15pmContine r (Ing nume_ing cantitate))" din if. r15pmEx1_initial :: Reteta -> Reteta -> Reteta r15pmEx1_initial Stop _ = Stop r15pmEx1_initial (R (Ing nume_ing cantitate) r) reteta_initiala = if cantitate == r15pmMaxIng reteta_initiala nume_ing && not (r15pmContine r (Ing nume_ing cantitate)) then R (Ing nume_ing cantitate) (r15pmEx1_initial r reteta_initiala) else r15pmEx1_initial r reteta_initiala r15pmEx1 :: Reteta -> Reteta r15pmEx1 r = r15pmEx1_initial r r -- Pentru testing: ex :: Reteta ex = R (Ing "faina" 500) (R (Ing "Oua" 4) (R (Ing "faina" 300) Stop)) retetaGoala :: Reteta retetaGoala = Stop reteta1 :: Reteta reteta1 = R (Ing "branza" 1) (R (Ing "Oua" 5) (R (Ing "brAnza" 20) (R (Ing "OUA" 0) Stop))) reteta2 :: Reteta reteta2 = R (Ing "branza" 1) (R (Ing "Oua" 5) (R (Ing "brAnza" 1) (R (Ing "OUA" 0) Stop))) -- Teste: -- 1. ex (dat in enunt): R (Ing "faina" 500) (R (Ing "Oua" 4) Stop) -- 2. testReteta: Stop -- 3. reteta1: R (Ing "Oua" 5) (R (Ing "brAnza" 20) Stop) -- 4. reteta2: R (Ing "Oua" 5) (R (Ing "brAnza" 1) Stop) -- b) -- Verifica daca doua ingrediente sunt egale ca si nume (case insensitive) si cantitate. instance Eq Ing where (Ing name1 quantity1) == (Ing name2 quantity2) = map toLower name1 == map toLower name2 && quantity1 == quantity2 -- Verifica daca reteta din primul parametru contine toate ingredientele din al doilea parametru. r15pmContineTot :: Reteta -> Reteta -> Bool r15pmContineTot _ Stop = True r15pmContineTot Stop _ = False r15pmContineTot r1 (R ing r) | r15pmContine r1 ing = r15pmContineTot r1 r | otherwise = False -- Ca doua retete sa fie egale, am folosit dubla incluziune. -- Adica prima reteta trebuie sa contina tot ce e in a doua si invers. instance Eq Reteta where a == b = let x = r15pmEx1 a in let y = r15pmEx1 b in r15pmContineTot x y && r15pmContineTot y x -- Pentru testing: r1 :: Reteta r1 = R (Ing "faina" 500) (R (Ing "oua" 4) (R (Ing "zahar" 500) (R (Ing "faina" 300) Stop))) r2 :: Reteta r2 = R (Ing "fAIna" 500) (R (Ing "zahar" 500) (R (Ing "Oua" 4) Stop )) r3 :: Reteta r3 = R (Ing "fAIna" 500) (R (Ing "zahar" 500) (R (Ing "Oua" 55) Stop)) r4 :: Reteta r4 = R (Ing "fAIna" 499) (R (Ing "zahar" 500) (R (Ing "Oua" 55) Stop)) r5 :: Reteta r5 = Stop r6 :: Reteta r6 = R (Ing "fAIna" 499) (R (Ing "zahar" 500) Stop) -- este continuta de r4 -- Teste: -- 1. r1 == r2 (dat in enunt): True -- 2. r2 == r3 (dat in enunt): False -- 3. r3 == r3: False -- 4. r1 == r5: False -- 5. r5 == r5: True -- 6. r1 == r1: True -- 7. r4 == r6: False -- 8. r6 == r4: False -- c) -- Combina 2 retete (duce b-ul la finalul lui a) r15pmCombina :: Reteta -> Reteta -> Reteta r15pmCombina a Stop = a r15pmCombina Stop a = a r15pmCombina (R ing Stop) b = R ing b r15pmCombina (R _ r) b = r15pmCombina r b data Arb = Leaf Int String | Node Arb Int String Arb deriving Show r15pmArbToReteta :: Arb -> Reteta r15pmArbToReteta (Leaf x nume) = R (Ing nume x) Stop r15pmArbToReteta (Node leftArb x nume rightArb) = let leftRightReteta = r15pmCombina (r15pmArbToReteta leftArb) (r15pmArbToReteta rightArb) in R (Ing nume x) leftRightReteta -- Exercitiul 2 data E x = A | M x Bool (E x) -- a) instance Foldable E where foldMap _ A = mempty foldMap f (M x _ e) = foldMap f e `mappend` f x -- Pentru testing: fTest0 :: Bool fTest0 = maximum (M 1 True (M 5 False (M 3 True (M 2 True A)))) == 3 fTest1 :: Bool fTest1 = maximum (M 1 True (M 5 False (M 8 True (M 2 True A)))) == 8 fTest2 :: Bool fTest2 = sum (M 1 True (M 5 True (M 8 True (M 2 True A)))) == 16 fTest3 :: Bool fTest3 = foldr (*) 1 (M 1 True (M 5 True (M 8 True A))) == 40 -- Teste: -- toate True -- b) class C e where cFilter :: (a -> Bool) -> e a -> e a toList :: e a -> [a] instance C E where cFilter _ A = A cFilter f (M x b e) | not (f x) = M x False (cFilter f e) | otherwise = M x b (cFilter f e) toList A = [] toList (M x b e) | b = x : toList e | otherwise = toList e -- Pentru testing: cTest0 :: Bool cTest0 = toList (cFilter (>2) (M 1 True (M 5 False (M 3 True (M 2 True A))))) == [3] cTest1 :: Bool cTest1 = toList (cFilter (>2) (M 1 True (M 5 True (M 3 True (M 2 True A))))) == [5, 3] cTest2 :: Bool cTest2 = toList (cFilter (> 100) (M 1 True (M 5 True (M 3 True (M 2 True A))))) == [] cTest3 :: Bool cTest3 = toList (cFilter (== 5) (M 1 True (M 5 False (M 3 True (M 2 True A))))) == [] cTest4 :: Bool cTest4 = toList (cFilter (== 5) (M 1 True (M 5 False (M 5 True A)))) == [5] -- Teste: -- toate True