diff --git a/.gitignore b/.gitignore index 3b5dbd594..4f5eb7387 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ TAGS # other .DS_Store .env +Dockerfile \ No newline at end of file diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 406deeaca..2a01629e0 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -209,31 +209,31 @@ So, the output in this example means that 'False' has type 'Bool'. > Try to guess first and then compare your expectations with GHCi output >>> :t True - +True :: Bool >>> :t 'a' - +'a' :: Char >>> :t 42 - +42 :: Num a => a A pair of boolean and char: >>> :t (True, 'x') - +(True, 'x') :: (Bool, Char) Boolean negation: >>> :t not - +not :: Bool -> Bool Boolean 'and' operator: >>> :t (&&) - +(&&) :: Bool -> Bool -> Bool Addition of two numbers: >>> :t (+) - +(+) :: Num a => a -> a -> a Maximum of two values: >>> :t max - +max :: Ord a => a -> a -> a You might not understand each type at this moment, but don't worry! You've only started your Haskell journey. Types will become your friends soon. @@ -301,43 +301,43 @@ expressions in GHCi functions and operators first. Remember this from the previous task? ;) >>> 1 + 2 - +3 >>> 10 - 15 - +-5 >>> 10 - (-5) -- negative constants require () - +15 >>> (3 + 5) < 10 - +True >>> True && False - +False >>> 10 < 20 || 20 < 5 - +True >>> 2 ^ 10 -- power - +1024 >>> not False - +True >>> div 20 3 -- integral division - +6 >>> mod 20 3 -- integral division remainder - +2 >>> max 4 10 - +10 >>> min 5 (max 1 2) - +2 >>> max (min 1 10) (min 5 7) - +5 Because Haskell is a __statically-typed__ language, you see an error each time you try to mix values of different types in situations where you are not @@ -428,7 +428,7 @@ task is to specify the type of this function. >>> squareSum 3 4 49 -} - +squareSum :: Int -> Int -> Int squareSum x y = (x + y) * (x + y) @@ -449,7 +449,7 @@ Implement the function that takes an integer value and returns the next 'Int'. function body with the proper implementation. -} next :: Int -> Int -next x = error "next: not implemented!" +next x = x + 1 {- | After you've implemented the function (or even during the implementation), you @@ -490,7 +490,8 @@ Implement a function that returns the last digit of a given number. whether it works for you! -} -- DON'T FORGET TO SPECIFY THE TYPE IN HERE -lastDigit n = error "lastDigit: Not implemented!" +lastDigit :: Int -> Int +lastDigit n = mod (abs n) 10 {- | @@ -520,7 +521,7 @@ branches because it is an expression and it must always return some value. satisfying the check will be returned and, therefore, evaluated. -} closestToZero :: Int -> Int -> Int -closestToZero x y = error "closestToZero: not implemented!" +closestToZero x y = if abs x < abs y then x else y {- | @@ -553,8 +554,13 @@ value after "=" where the condition is true. Casual reminder about adding top-level type signatures for all functions :) -} - -mid x y z = error "mid: not implemented!" +mid :: Int -> Int -> Int -> Int +mid x y z + | x < y && x < z && y < z = y + | z < x && z < y && x < y = x + | z < x && z < y && y < x = y + | y < x && y < z && x < z = x + | otherwise = z {- | =βš”οΈ= Task 8 @@ -568,7 +574,14 @@ True >>> isVowel 'x' False -} -isVowel c = error "isVowel: not implemented!" +isVowel :: Char -> Bool +isVowel c + | c == 'a' = True + | c == 'e' = True + | c == 'i' = True + | c == 'o' = True + | c == 'u' = True + | otherwise = False {- | @@ -632,8 +645,21 @@ Try to introduce variables in this task (either with let-in or where) to avoid specifying complex expressions. -} -sumLast2 n = error "sumLast2: Not implemented!" +sumLast2 :: Int -> Int +sumLast2 n = mod10 (div10 n) + mod10 n + where + div10 :: Int -> Int + div10 x = div (abs x) 10 + + mod10 :: Int -> Int + mod10 x = mod (abs x) 10 +sumLast2' :: (Integral a, Num a) => a -> a +sumLast2' n = mdiv10 + mod1 + where + mdiv10 = mod c 10 + mod1 = d + (c, d) = divMod (abs n) 10 {- | =πŸ’£= Task 10* @@ -653,7 +679,10 @@ You need to use recursion in this task. Feel free to return to it later, if you aren't ready for this boss yet! -} -firstDigit n = error "firstDigit: Not implemented!" +firstDigit :: Int -> Int +firstDigit n = if abs n < 10 + then abs n + else firstDigit (abs n `div` 10) {- diff --git a/src/Chapter2.hs b/src/Chapter2.hs index b98ceaf7d..0d0438a68 100644 --- a/src/Chapter2.hs +++ b/src/Chapter2.hs @@ -136,43 +136,44 @@ functions in GHCi and insert the corresponding resulting output below: List of booleans: >>> :t [True, False] - +[True, False] :: [Bool] String is a list of characters: >>> :t "some string" - +"some string" :: String Empty list: >>> :t [] - +[] :: [a] Append two lists: >>> :t (++) - +(++) :: [a] -> [a] -> [a] Prepend an element at the beginning of a list: >>> :t (:) - +(:) :: a -> [a] -> [a] Reverse a list: >>> :t reverse +reverse :: [a] -> [a] Take first N elements of a list: >>> :t take - +take :: Int -> [a] -> [a] Create a list from N same elements: >>> :t replicate - +replicate :: Int -> a -> [a] Split a string by line breaks: >>> :t lines - +lines :: String -> [String] Join a list of strings with line breaks: >>> :t unlines - +unlines :: [String] -> String -} @@ -186,32 +187,43 @@ Evaluate the following expressions in GHCi and insert the answers. Try to guess first, what you will see. >>> [10, 2] ++ [3, 1, 5] +[10,2,3,1,5] >>> [] ++ [1, 4] -- [] is an empty list +[1,4] >>> 3 : [1, 2] +[3,1,2] >>> 4 : 2 : [5, 10] -- prepend multiple elements +[4,2,5,10] >>> [1 .. 10] -- list ranges +[1,2,3,4,5,6,7,8,9,10] >>> [10 .. 1] +[] >>> [10, 9 .. 1] -- backwards list with explicit step +[10,9,8,7,6,5,4,3,2,1] >>> length [4, 10, 5] -- list length +3 >>> replicate 5 True +[True,True,True,True,True] >>> take 5 "Hello, World!" +"Hello" >>> drop 5 "Hello, World!" +", World!" >>> zip "abc" [1, 2, 3] -- convert two lists to a single list of pairs +[('a',1),('b',2),('c',3)] >>> words "Hello Haskell World!" -- split the string into the list of words - - +["Hello","Haskell","World!"] πŸ‘©β€πŸ”¬ Haskell has a lot of syntax sugar. In the case with lists, any list literal like "[3, 1, 2]" is syntax sugar for prepending elements @@ -336,7 +348,12 @@ from it! ghci> :l src/Chapter2.hs -} subList :: Int -> Int -> [a] -> [a] -subList = error "subList: Not implemented!" +subList _ _ [] = [] +subList 0 0 b = take 1 b +subList _ 0 _ = [] +subList x y b = if x >= 0 + then take (y - x + 1) $ drop x b + else [] {- | =βš”οΈ= Task 4 @@ -349,7 +366,10 @@ Implement a function that returns only the first half of a given list. "b" -} -- PUT THE FUNCTION TYPE IN HERE -firstHalf l = error "firstHalf: Not implemented!" + +firstHalf :: [a] -> [a] +firstHalf [] = [] +firstHalf a = take ((length a) `div` 2) a {- | @@ -501,7 +521,11 @@ True >>> isThird42 [42, 42, 0, 42] False -} -isThird42 = error "isThird42: Not implemented!" +isThird42 :: (Eq a, Num a) => [a] -> Bool +isThird42 [] = False +isThird42 [_] = False +isThird42 [_, _] = False +isThird42 ( _ : _ : x : _ ) = x == 42 {- | @@ -606,7 +630,8 @@ Implement a function that duplicates each element of the list -} duplicate :: [a] -> [a] -duplicate = error "duplicate: Not implemented!" +duplicate [] = [] +duplicate (x:xs) = x : x : duplicate xs {- | @@ -621,7 +646,20 @@ Write a function that takes elements of a list only in even positions. >>> takeEven [2, 1, 3, 5, 4] [2,3,4] -} -takeEven = error "takeEven: Not implemented!" +-- takeEven :: [a] -> [a] +-- takeEven [] = [] +-- takeEven (x:xs) = recursiveEven 0 (x : xs) +-- where +-- recursiveEven :: Int -> [a] -> [a] +-- recursiveEven _ [] = [] +-- recursiveEven c (x:xs) = if mod c 2 == 0 +-- then x : recursiveEven (c + 1) xs +-- else recursiveEven (c + 1) xs +takeEven :: [a] -> [a] +takeEven [] = [] +takeEven [x] = [x] +takeEven ( x : _ : xs ) = [x] ++ takeEven xs + {- | =πŸ›‘= Higher-order functions @@ -727,8 +765,13 @@ value of the element itself πŸ•― HINT: Use combination of 'map' and 'replicate' -} +-- smartReplicate :: [Int] -> [Int] +-- smartReplicate [] = [] +-- smartReplicate (x:xs) = (replicate x x) ++ smartReplicate xs +-- dont understod how to use map smartReplicate arr = map (\x -> replicate x x) arr + smartReplicate :: [Int] -> [Int] -smartReplicate l = error "smartReplicate: Not implemented!" +smartReplicate = concatMap (\x -> replicate x x) {- | =βš”οΈ= Task 9 @@ -741,8 +784,12 @@ the list with only those lists that contain a passed element. πŸ•― HINT: Use the 'elem' function to check whether an element belongs to a list -} -contains = error "contains: Not implemented!" - +contains :: Int -> [[Int]] -> [[Int]] +contains _ [] = [] +contains _ [[]] = [] +contains b (x:xs) = if (elem b x) == True + then [x] ++ contains b xs + else contains b xs {- | =πŸ›‘= Eta-reduction @@ -781,13 +828,15 @@ Let's now try to eta-reduce some of the functions and ensure that we mastered the skill of eta-reducing. -} divideTenBy :: Int -> Int -divideTenBy x = div 10 x +divideTenBy = div 10 -- TODO: type ;) -listElementsLessThan x l = filter (< x) l +listElementsLessThan :: Int -> [Int] -> [Int] +listElementsLessThan x = filter (< x) -- Can you eta-reduce this one??? -pairMul xs ys = zipWith (*) xs ys +pairMul :: [Int] -> [Int] -> [Int] +pairMul = zipWith (*) {- | =πŸ›‘= Lazy evaluation @@ -842,7 +891,9 @@ list. πŸ•― HINT: Use the 'cycle' function -} -rotate = error "rotate: Not implemented!" +rotate :: Int -> [a] -> [a] +rotate _ [] = [] +rotate n arr = drop n $ take ((length arr) + n) $ cycle arr {- | =πŸ’£= Task 12* @@ -858,9 +909,17 @@ and reverses it. function, but in this task, you need to implement it manually. No cheating! -} -rewind = error "rewind: Not Implemented!" +rewind' :: [a] -> [a] +rewind' [] = [] +rewind' (x:xs) = (rewind' xs) ++ [x] +rewind :: [a] -> [a] +rewind [] = [] +rewind arr = head pegaproximo : rewind (tail pegaproximo) + where + pegaproximo = rotate (length arr - 1) arr + {- You did it! Now it is time to open pull request with your changes and summon @vrom911 for the review! diff --git a/src/Chapter3.hs b/src/Chapter3.hs index 061811064..9625d0187 100644 --- a/src/Chapter3.hs +++ b/src/Chapter3.hs @@ -52,6 +52,9 @@ provide more top-level type signatures, especially when learning Haskell. {-# LANGUAGE InstanceSigs #-} module Chapter3 where +import Data.Either +-- import LearnHaskell (TreasureChest(TreasureChest)) +-- import Distribution.PackageDescription (Library) {- =πŸ›‘= Types in Haskell @@ -344,6 +347,28 @@ of a book, but you are not limited only by the book properties we described. Create your own book type of your dreams! -} +data Book = MkBook + { bookName :: String + , bookCover :: String + , bookAuthor :: String + , bookLanguage :: String + , bookPages :: Int + , bookRating :: Int + } deriving (Show) + +{- +livrinho = MkBook + { bookName = "meu livro" + , bookCover = "wow" + , bookAuthor = "Adriano Waltrick" + , bookLanguage = "Portuguese" + , bookPages = 100 + , bookRating = 10 + } + +livrinho = MkBook { bookName = "meu livro", bookCover = "wow", bookAuthor = "Adriano Waltrick", bookLanguage = "Portuguese", bookPages = 100, bookRating = 10} +-} + {- | =βš”οΈ= Task 2 @@ -376,6 +401,40 @@ after the fight. The battle has the following possible outcomes: -} +data Knight = MkKnight + { health :: Int + , attack :: Int + , gold :: Int + } deriving (Show) + + +data Monster = MkMonster + { mHealth :: Int + , mAttack :: Int + , mGold :: Int + } deriving (Show) + +fighter1 :: Knight +fighter1 = MkKnight + { health = 100 + , attack = 10 + , gold = 0 + } + +dragon1 :: Monster +dragon1 = MkMonster + { mHealth = 10 + , mAttack = 10 + , mGold = 10 + } + +fight :: Monster -> Knight -> Int +fight monster knight + | mHealth monster <= 0 = gold knight + mGold monster + | health knight <= 0 = -1 + | otherwise = fight (MkMonster (mHealth monster - attack knight) (mAttack monster) (mGold monster)) (MkKnight (health knight - mAttack monster) (attack knight) (gold knight)) + + {- | =πŸ›‘= Sum types @@ -462,6 +521,15 @@ Create a simple enumeration for the meal types (e.g. breakfast). The one who comes up with the most number of names wins the challenge. Use your creativity! -} +data MealType + = Nescau + | PaoComLeite + | BolachaSalgada + | BolachaDoce + | BolachaRecheada + | Biscoito + | Brigadeiro + {- | =βš”οΈ= Task 4 @@ -482,6 +550,96 @@ After defining the city, implement the following functions: and at least 10 living __people__ inside in all houses of the city in total. -} +data Castle = MkCastle + { castleName :: String + } deriving (Eq, Show) + +data Wall = MkWall + { size :: Int + } deriving (Show) + +data ChurchData = MkChurch + { churchName :: String + } deriving (Show) + +data LibraryData = MkLibrary + { libraryName :: String + } deriving (Show) + +data ChurchOrLibrary + = Church ChurchData + | Library LibraryData + deriving (Show) + +data PeopleInsideHouse + = None + | One + | Two + | Three + | Four + deriving (Show, Eq, Ord, Enum) + +data House = MkHouse + { people :: PeopleInsideHouse + } deriving (Show) + +data City = MkCity + { castle :: Maybe Castle + , wall :: Maybe Wall + , churchOrLibrary :: Maybe ChurchOrLibrary + , houses :: [House] + } deriving (Show) + +igreja1 :: ChurchOrLibrary +igreja1 = Church (MkChurch "Igreja1") + +buildCastle :: City -> String -> City +buildCastle (MkCity xcastle xwall xchurchOrLibrary xhouses) name = + if xcastle == Nothing then MkCity (Just (MkCastle name)) Nothing Nothing [] + else MkCity (Just (MkCastle name)) xwall xchurchOrLibrary xhouses + +brasilCastle :: Castle +brasilCastle = MkCastle "Brasil Castle" + +argentinaCastle :: Castle +argentinaCastle = MkCastle "Argentina Castle" + +saoPaulo :: City +saoPaulo = (MkCity (Just brasilCastle) (Just (MkWall 3)) (Just igreja1) [(MkHouse One)]) + +novoCastelo :: City +novoCastelo = buildCastle saoPaulo "Novo Nome" + +buildHouse :: City -> PeopleInsideHouse -> City +buildHouse (MkCity xcastle xwall xchurchOrLibrary xhouses) p = + MkCity xcastle xwall xchurchOrLibrary (xhouses ++ [(MkHouse p)]) + +{- buildHouse saoPaulo Two -} + +{- +✦ buildWalls β€” build walls in the city. But since building walls is a + complicated task, walls can be built only if the city has a castle + and at least 10 living __people__ inside in all houses of the city in total. +-} + +countPeoples :: City -> Int +countPeoples (MkCity _ _ _ []) = 0 +countPeoples (MkCity xcastle xwall xchurchOrLibrary ((MkHouse p):xs)) = + (fromEnum p) + (countPeoples (MkCity xcastle xwall xchurchOrLibrary xs)) + +countPeoplesArray :: [House] -> Int +countPeoplesArray [] = 0 +countPeoplesArray ((MkHouse p):xs) = (fromEnum p) + countPeoplesArray xs + +buildWalls :: City -> Int -> Maybe City +buildWalls (MkCity (Just (MkCastle _)) Nothing (Just _) []) _ = Nothing +buildWalls (MkCity Nothing Nothing Nothing []) _ = Nothing +buildWalls (MkCity Nothing _ _ []) _ = Nothing +buildWalls (MkCity (Just _) Nothing Nothing []) _ = Nothing +buildWalls (MkCity xcastle (Just (MkWall iwall)) xchurchOrLibrary xhouses) nwalls = + if countPeoplesArray xhouses < 10 then Nothing + else Just (MkCity xcastle (Just (MkWall (nwalls + iwall))) xchurchOrLibrary xhouses) + {- =πŸ›‘= Newtypes @@ -570,21 +728,24 @@ data Player = Player , playerStrength :: Int } -calculatePlayerDamage :: Int -> Int -> Int -calculatePlayerDamage attack strength = attack + strength +newtype PlayerAttack = MkPlayerAttack Int +newtype PlayerStrength = MkPlayerStrength Int + +calculatePlayerDamage :: PlayerAttack -> PlayerStrength -> Int +calculatePlayerDamage (MkPlayerAttack a) (MkPlayerStrength s) = a + s calculatePlayerDefense :: Int -> Int -> Int calculatePlayerDefense armor dexterity = armor * dexterity calculatePlayerHit :: Int -> Int -> Int -> Int -calculatePlayerHit damage defense health = health + defense - damage +calculatePlayerHit damage defense health1 = health1 + defense - damage -- The second player hits first player and the new first player is returned hitPlayer :: Player -> Player -> Player hitPlayer player1 player2 = let damage = calculatePlayerDamage - (playerAttack player2) - (playerStrength player2) + (MkPlayerAttack (playerAttack player2)) + (MkPlayerStrength (playerStrength player2)) defense = calculatePlayerDefense (playerArmor player1) (playerDexterity player1) @@ -755,6 +916,22 @@ parametrise data types in places where values can be of any general type. maybe-treasure ;) -} +data DragonData = MkDragon + { magicPower :: Int + } deriving (Show) + +data TreasureChestData a = MkTreasureChest + { goldOnChest :: a + } deriving (Show) + +data DragonLairData a = MkDragonLair + { dragon :: Maybe DragonData, + treasureChest :: Maybe (TreasureChestData a) + } deriving (Show) + + + + {- =πŸ›‘= Typeclasses @@ -912,6 +1089,54 @@ Implement instances of "Append" for the following types: class Append a where append :: a -> a -> a +data GoldData = MkGold + { totalGold :: Int + } deriving (Eq, Show) + +instance Append GoldData where + append :: GoldData -> GoldData -> GoldData + append loot1 loot2 = MkGold (totalGold loot1 + totalGold loot2) + +newtype Gold = Gold Int + deriving (Show) + +instance Append Gold where + append :: Gold -> Gold -> Gold + append (Gold a) (Gold b) = Gold (a + b) + +data List a + = Empty + | Cons a (List a) + deriving (Eq, Show) + +instance Append (List b) where + append :: List a -> List a -> List a + append list1 Empty = list1 + append Empty list1 = list1 + append (Cons valor1 Empty) (Cons valor2 Empty) = Cons valor1 (Cons valor2 Empty) + append (Cons valor1 lista1) (Cons valor2 Empty) = Cons valor1 (Cons valor2 lista1) + append (Cons valor1 lista1) (Cons valor2 lista2) = append (Cons valor1 (Cons valor2 lista1)) lista2 + +instance Append Int where + append :: Int -> Int -> Int + append a b = a + b + +instance (Append a) => Append [a] where + append :: [a] -> [a] -> [a] + append arr1 arr2 = arr1 ++ arr2 + +-- instance Append String where +-- append :: a -> a -> a +-- append arr1 arr2 = arr1 ++ arr2 + +instance (Append a) => Append (Maybe a) where + append :: Maybe a -> Maybe a -> Maybe a + append Nothing Nothing = Nothing + append container1 Nothing = container1 + append Nothing container1 = container1 + append (Just s1) (Just s2) = Just (append s1 s2) + + {- =πŸ›‘= Standard Typeclasses and Deriving @@ -973,6 +1198,56 @@ implement the following functions: πŸ•― HINT: to implement this task, derive some standard typeclasses -} + +data DiasDaSemana + = Segunda -- 0 + | Terca + | Quarta + | Quinta + | Sexta -- 4 + | Sabado + | Domingo + deriving (Show, Eq, Ord) + +isWeekend :: DiasDaSemana -> Bool +isWeekend a + | a == Sabado = True + | a == Domingo = True + | otherwise = False + +nextDay :: DiasDaSemana -> DiasDaSemana +nextDay Domingo = Segunda +nextDay a = toEnum ((fromEnum a) + 1) + +daysToParty :: DiasDaSemana -> Int +daysToParty Sexta = 0 +daysToParty Sabado = 2 + daysToParty Segunda +daysToParty Domingo = 1 + daysToParty Segunda +-- o /= Sexta Γ© um lambda infix -- cria a lista de a atΓ© sexta, separa num array e conta qntos tem +daysToParty a = length $ takeWhile ( /= Sexta) [a .. Sexta] + +instance Enum DiasDaSemana where + toEnum :: Int -> DiasDaSemana + toEnum 0 = Segunda + toEnum 1 = Terca + toEnum 2 = Quarta + toEnum 3 = Quinta + toEnum 4 = Sexta + toEnum 5 = Sabado + toEnum 6 = Domingo + + fromEnum :: DiasDaSemana -> Int + fromEnum Segunda = 0 + fromEnum Terca = 1 + fromEnum Quarta = 2 + fromEnum Quinta = 3 + fromEnum Sexta = 4 + fromEnum Sabado = 5 + fromEnum Domingo = 6 + +daysToPartyInstance :: DiasDaSemana -> Int +daysToPartyInstance day = fromEnum (Sexta :: DiasDaSemana) - fromEnum day + {- =πŸ’£= Task 9* @@ -1007,6 +1282,93 @@ properties using typeclasses, but they are different data types in the end. Implement data types and typeclasses, describing such a battle between two contestants, and write a function that decides the outcome of a fight! -} +{- + +1) A knight can attack, drink a health potion, cast a spell to increase their defence. +while knights also have a defence. + +2) A monster can only attack or run away. Monsters have only health and attack + +3) They do their activities in turns, i.e. one fighter goes first, then +the other goes second, then the first again, and so on, until one of them wins. + +4) Both knight and monster have a sequence of actions they can do + +5) each fighter starts with some list of actions they can do + +6) The fight ends when the health of one fighter becomes zero or less. +-} + +data Actions = Attack | DrinkToCure | CastDef | RunAway + deriving (Show, Eq, Ord) + +data ActionChange = Hero | Antagonist + deriving (Show, Eq, Ord) + +data NewKnight = MkNewKnight + { newKHealth :: Int + , newKDefense :: Int + } deriving (Show) + +data NewMonster = MkNewMonster { newMoHealth :: Int } + deriving (Show) + +class Luta a where + toAttack :: a -> a + +instance Luta NewMonster where + toAttack :: NewMonster -> NewMonster + toAttack (MkNewMonster mhealth) = MkNewMonster (mhealth - 1) + +instance Luta NewKnight where + toAttack :: NewKnight -> NewKnight + toAttack (MkNewKnight khealth kdef) = if kdef > 0 + then MkNewKnight (khealth) (kdef -1) + else MkNewKnight (khealth - 1) kdef + +-- todo retornar o either auqi nao ficou legal +parseActionKnight :: NewKnight -> Actions -> NewKnight +parseActionKnight (MkNewKnight khealth kdef) action + | action == DrinkToCure = (MkNewKnight (khealth + 1) kdef) + | action == CastDef = (MkNewKnight khealth (kdef + 1)) + | otherwise = (MkNewKnight khealth kdef) + +parseActionMonster :: NewMonster -> Actions -> NewMonster +parseActionMonster (MkNewMonster khealth) action + | action == RunAway = (MkNewMonster 0) + | otherwise = (MkNewMonster khealth) + +rotate :: Int -> [a] -> [a] +rotate _ [] = [] +rotate n arr = drop n $ take ((length arr) + n) $ cycle arr + + +francisco = (MkNewKnight 13 2) +lizzard = (MkNewMonster 5) + +tank = (MkNewKnight 100 2) +stronger = (MkNewMonster 13) + +actionOrder = [Hero, Antagonist] +kaction = [Attack, DrinkToCure, CastDef] +maction = [Attack, Attack, Attack, Attack, Attack, Attack, Attack, Attack, Attack, Attack, RunAway] + +figthToDeath :: NewKnight -> NewMonster -> [Actions] -> [Actions] -> [ActionChange] -> String +figthToDeath (MkNewKnight khealth kdef) (MkNewMonster mhealth) arrK arrM order + | head order == Hero = if (head arrK) == Attack then (if mhealth > 0 + then figthToDeath (MkNewKnight khealth kdef) (toAttack (MkNewMonster mhealth)) (rotate 1 arrK) (rotate 1 arrM) (rotate 1 order) + else "!!Hero wins!! Hero life:" ++ (show khealth) ++ " - Monster life: " ++ (show mhealth) ) + else figthToDeath (MkNewKnight khealth kdef) (MkNewMonster mhealth) (rotate 1 arrK) (rotate 1 arrM) (rotate 1 order) + | otherwise = if (head arrM) == Attack then (if khealth > 0 + then figthToDeath (toAttack (MkNewKnight khealth kdef)) (MkNewMonster mhealth) (rotate 1 arrK) (rotate 1 arrM) (rotate 1 order) + else "Monster wins!! Hero life:" ++ (show khealth) ++ " - Monster life: " ++ (show mhealth) ) + else figthToDeath (MkNewKnight khealth kdef) (MkNewMonster mhealth) (rotate 1 arrK) (rotate 1 arrM) (rotate 1 order) + +-- to execute +-- figthToDeath francisco lizzard kaction maction actionOrder +-- figthToDeath tank stronger kaction maction actionOrder + +-- WOW - thas hard!! {- @@ -1018,4 +1380,4 @@ and summon @vrom911 for the review! =πŸ“œ= Additional resources Deriving: https://kowainik.github.io/posts/deriving Extensions: https://kowainik.github.io/posts/extensions --} +-} \ No newline at end of file diff --git a/src/Chapter4.hs b/src/Chapter4.hs index caec5a95d..7d26c543b 100644 --- a/src/Chapter4.hs +++ b/src/Chapter4.hs @@ -40,6 +40,7 @@ Perfect. Let's crush this! {-# LANGUAGE InstanceSigs #-} module Chapter4 where +-- import System.Win32 (xBUTTON1) {- | =πŸ›‘= Kinds @@ -267,6 +268,22 @@ instance Functor Maybe where @ -} +{- + -- response: + Any function applied to x doesn't make sense as we have to access what's inside x (a) and transform to b (a -> b) + And Functor Maybe already exists. +-} + +-- data Maybe2 e +-- = Just2 e +-- | Nothing2 + +-- instance Functor Maybe2 where +-- fmap :: (a -> b) -> Maybe2 a -> Maybe2 b +-- fmap f (Just2 a) = Just2 (f a) +-- fmap _ x = x + + {- | =βš”οΈ= Task 2 @@ -281,7 +298,6 @@ data Secret e a | Reward a deriving (Show, Eq) - {- | Functor works with types that have kind `* -> *` but our 'Secret' has kind `* -> * -> *`. What should we do? Don't worry. We can partially @@ -292,7 +308,22 @@ values and apply them to the type level? -} instance Functor (Secret e) where fmap :: (a -> b) -> Secret e a -> Secret e b - fmap = error "fmap for Box: not implemented!" + fmap _ (Trap e) = Trap e + fmap f (Reward a) = Reward (f a) + +-- example +addOneGold :: (Integral a, Num a) => (Secret e a) -> (Secret e a) +addOneGold (Trap e) = Trap e +addOneGold (Reward a) = Reward (a + 1) + +addToChest :: (Integral a, Num a, Num e) => a -> (Secret e a) +addToChest a + | a == 0 = (Trap 0) + | otherwise = Reward a + +-- addOneGold (Reward 1) +-- addOneGold $ Reward 1 +-- fmap (addToChest) (Reward 1) {- | =βš”οΈ= Task 3 @@ -305,6 +336,20 @@ typeclasses for standard data types. data List a = Empty | Cons a (List a) + deriving (Show) + +instance Functor List where + fmap :: (a -> b) -> List a -> List b + fmap _ Empty = Empty + fmap f (Cons a (blist)) = Cons (f a) (fmap f blist) + + +list1 = Empty +list2 = Cons 10 (Cons 20 Empty) +list3 = Cons 10 (Cons 20 (Cons 30 Empty)) + +-- fmap (+10) list3 +-- Cons 20 (Cons 30 (Cons 40 Empty)) {- | =πŸ›‘= Applicative @@ -471,10 +516,27 @@ Implement the Applicative instance for our 'Secret' data type from before. -} instance Applicative (Secret e) where pure :: a -> Secret e a - pure = error "pure Secret: Not implemented!" - + pure = Reward (<*>) :: Secret e (a -> b) -> Secret e a -> Secret e b - (<*>) = error "(<*>) Secret: Not implemented!" + (Trap a) <*> _ = Trap a + _ <*> (Trap a) = Trap a + (Reward f) <*> i = fmap f i + +-- tests +secret1 = Trap "you die" +secret2 = Reward 10 +secret3 = Reward 20 + +-- die +-- fmap (+10) secret1 + +-- 50 +-- fmap (+40) secret2 + +-- 20 +-- Reward (+10) <*> Reward 10 + +-- hell yeah!! {- | =βš”οΈ= Task 5 @@ -488,6 +550,27 @@ Implement the 'Applicative' instance for our 'List' type. type. -} +list4 = Cons (+5) Empty +list5 = Cons (+5) (Cons (+6) Empty) +list6 = Cons (+1) (Cons (+2) (Cons (+3) Empty)) +list7 = Cons 1 (Cons 2 (Cons 3 Empty)) + +combineList :: List a -> List a -> List a +combineList Empty l1 = l1 +combineList l1 Empty = l1 +combineList (Cons x xs) l2 = Cons x (combineList xs l2) + +instance Applicative List where + pure :: a -> List a + pure a = Cons a Empty + (<*>) :: List (a -> b) -> List a -> List b + Empty <*> _ = Empty + _ <*> Empty = Empty + -- (Cons f l) <*> i = fmap f i + -- (Cons f (Cons l emp)) <*> i = fmap l i + (Cons f emp) <*> i = combineList (fmap f i) (emp <*> i) + +-- list6 <*> list7 {- | =πŸ›‘= Monad @@ -597,9 +680,28 @@ concepts in the end. Implement the 'Monad' instance for our 'Secret' type. -} +-- instance Monad (Secret e) where +-- (>>=) :: Secret e a -> (a -> Secret e b) -> Secret e b +-- (>>=) = error "bind Secret: Not implemented!" + instance Monad (Secret e) where (>>=) :: Secret e a -> (a -> Secret e b) -> Secret e b - (>>=) = error "bind Secret: Not implemented!" + (Trap c) >>= f = Trap c + (Reward c) >>= f = f c + +test :: Int -> Secret Int Int +test n + | n == 1 = Trap 1 + | otherwise = Reward (n + 1) + + + +-- test +-- Trap 11 >>= test +-- Reward 11 >>= test + + + {- | =βš”οΈ= Task 7 @@ -610,6 +712,24 @@ Implement the 'Monad' instance for our lists. maybe a few) to flatten lists of lists to a single list. -} +flattenList :: List (List a) -> List a +flattenList Empty = Empty +flattenList (Cons x xs) = combineList x (flattenList xs) + +instance Monad List where + (>>=) :: List a -> (a -> List b) -> List b + list1 >>= func = flattenList (fmap func list1) + +addOneOnList :: (Integral a, Num a) => a -> List a +addOneOnList n = Cons (n + 1) Empty + +listC = Cons list2 Empty + +-- exemplo de uso +-- list2 >>= addOneOnList +-- list3 >>= addOneOnList +-- list3 >>= addOneOnList >>= addOneOnList + {- | =πŸ’£= Task 8*: Before the Final Boss @@ -628,7 +748,28 @@ Can you implement a monad version of AND, polymorphic over any monad? πŸ•― HINT: Use "(>>=)", "pure" and anonymous function -} andM :: (Monad m) => m Bool -> m Bool -> m Bool -andM = error "andM: Not implemented!" +andM contextB1 contextB2 = contextB1 >>= \f -> if f then contextB2 else pure False + +tJust1 = Just True +tJust2 = Just False +tJust3 = Nothing +tEither1 = Left True +tEither2 = Left False +tEither3 = Right True + +-- Nothing and _ = False +-- _ and Nothing = False +-- Just True and Just True = True +-- Just True and Just False = False +-- Just False and Just False = False +-- Just False and Just True = False + +-- andM tJust1 tJust1 = True +-- andM tJust1 tJust2 = False +-- andM TJust2 tJust1 = False + +half2 :: (Monad m) => m Integer -> m Integer +half2 monadInt = monadInt >>= \x -> if even x then pure (div x 2) else pure 0 {- | =πŸ‰= Task 9*: Final Dungeon Boss @@ -665,12 +806,52 @@ Specifically, ❃ Implement a polymorphic binary tree type that can store any elements inside its nodes + ❃ Implement the Functor instance for Tree + ❃ Implement the reverseTree function that reverses the tree and each subtree of a tree + ❃ Implement the function to convert Tree to list -} +data MyBtree a + = BEmpty + | MkMyBTree (MyBtree a) a (MyBtree a) + deriving (Show) + +tree1 = BEmpty +tree2 = MkMyBTree (BEmpty) 10 (BEmpty) +tree3 = MkMyBTree (MkMyBTree (BEmpty) 20 (BEmpty)) 10 (MkMyBTree (BEmpty) 20 (BEmpty)) +tree4 = MkMyBTree (MkMyBTree ((MkMyBTree (BEmpty) 30 (BEmpty))) 20 ((MkMyBTree (BEmpty) 30 (BEmpty)))) 10 (MkMyBTree ((MkMyBTree (BEmpty) 30 (BEmpty))) 20 ((MkMyBTree (BEmpty) 30 (BEmpty)))) +tree5 = MkMyBTree (MkMyBTree ((MkMyBTree (BEmpty) 4 (BEmpty))) 6 ((MkMyBTree (BEmpty) 3 (BEmpty)))) 7 (MkMyBTree ((MkMyBTree (BEmpty) 2 (BEmpty))) 5 ((MkMyBTree (BEmpty) 1 (BEmpty)))) +treeString = MkMyBTree (MkMyBTree (BEmpty) "Adriano" (BEmpty)) "Joao" (MkMyBTree (BEmpty) "AndrΓ©" (BEmpty)) + +instance Functor MyBtree where + fmap :: (a -> b) -> MyBtree a -> MyBtree b + fmap _ BEmpty = BEmpty + fmap f (MkMyBTree (ltree) a (rtree)) = MkMyBTree (fmap f rtree) (f a) (fmap f rtree) + +-- fmap (+10) tree2 + +reverseMyBTree :: MyBtree a -> MyBtree a +reverseMyBTree BEmpty = BEmpty +reverseMyBTree (MkMyBTree ltree x rtree) = MkMyBTree (reverseMyBTree rtree) x (reverseMyBTree ltree) + +convertToArr :: MyBtree a -> [a] +convertToArr BEmpty = [] +convertToArr (MkMyBTree (ltree) x (rtree)) = [x] ++ convertToArr ltree ++ convertToArr rtree + +-- convertToArr tree4 + +makeListFromTree :: MyBtree a -> List a +makeListFromTree BEmpty = Empty +makeListFromTree (MkMyBTree (ltree) x (rtree)) = combineList (Cons x (makeListFromTree ltree)) (makeListFromTree rtree) + + +-- makeListFromTree tree4 + +{-- huuuu ulll - it finish!!! -} {- You did it! Now it is time to open pull request with your changes