From e0d646213d04815a0591ee87301fa50010387076 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 18:09:49 +0800 Subject: [PATCH 01/15] chore: completed Task 1 --- src/Chapter1.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 04fed0db..a47cc1ee 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. From 0d9b2fabc713a53b30437585e6aeb5de6457a543 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 20:38:38 +0800 Subject: [PATCH 02/15] chore: completed Task 2 --- src/Chapter1.hs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index a47cc1ee..27c5aa36 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -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 From cf1058d6e63645e878c17fcd246e9e7eac963e86 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 20:51:10 +0800 Subject: [PATCH 03/15] chore: completed Task 3 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 27c5aa36..787ab9f8 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -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) From 51dfa5228e799886cb41c4b4c668274ec1cdbe03 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:44:58 +0800 Subject: [PATCH 04/15] chore: completed Task 4 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 787ab9f8..13ef4095 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -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 From 598f085559c41216b1baeb40bd4babfd03db0cab Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:54:01 +0800 Subject: [PATCH 05/15] chore: completed Task 5 --- src/Chapter1.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 13ef4095..70ed6d42 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -489,8 +489,8 @@ Implement a function that returns the last digit of a given number. results. Or you can try to guess the function name, search for it and check 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 {- | From 144f6964c4045c04f491880e0b39c911490bf6fd Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:59:30 +0800 Subject: [PATCH 06/15] chore: completed Task 6 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 70ed6d42..6c934d2f 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -520,7 +520,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 {- | From ea6da157684b4c89bd2e208e86da0dc9834e392a Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:04:01 +0800 Subject: [PATCH 07/15] chore: completed Task 7 --- src/Chapter1.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 6c934d2f..5f595d85 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -553,8 +553,11 @@ 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) || (x < y && x > z) = x + | (y > x && y < z) || (y < x && y > z) = y + | otherwise = z {- | =⚔️= Task 8 From 457aff61ad1f62c734d915f90ef81afebaafc77d Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:15:51 +0800 Subject: [PATCH 08/15] chore: completed Task 8 --- src/Chapter1.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 5f595d85..75aa4830 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -571,7 +571,14 @@ True >>> isVowel 'x' False -} -isVowel c = error "isVowel: not implemented!" +isVowel :: Char -> Bool +isVowel c + | c == 'a' || c == 'A' = True + | c == 'e' || c == 'E' = True + | c == 'i' || c == 'I' = True + | c == 'o' || c == 'O' = True + | c == 'u' || c == 'U' = True + | otherwise = False {- | From bb37053333af4fea98f882e7d75c4846871eaf12 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:41:09 +0800 Subject: [PATCH 09/15] chore: completed Task 9 --- src/Chapter1.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 75aa4830..64ffc9a3 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -641,9 +641,11 @@ Implement a function that returns the sum of the last two digits of a number. 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 = + let (remaining, last1) = divMod (abs n) 10 + last2 = mod remaining 10 + in (last1 + last2) {- | =💣= Task 10* From 9da85e4a17427de099957cb7de59e19176db5903 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:47:49 +0800 Subject: [PATCH 10/15] chore: completed Task 10* --- src/Chapter1.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 64ffc9a3..ba91fc03 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -664,8 +664,8 @@ Implement a function that returns the first digit of a given number. 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 (div n 10) {- From 11749ee990931c3a9805fff52ebece1aa0f7a54f Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Tue, 18 Oct 2022 09:36:12 +0800 Subject: [PATCH 11/15] fix: fixed failing test --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index ba91fc03..4c08e59a 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -213,7 +213,7 @@ True :: Bool >>> :t 'a' 'a' :: Char >>> :t 42 -42 :: Num a => a +42 :: Num p => p A pair of boolean and char: >>> :t (True, 'x') From a7b313f9f11186f379ed31fbdd99f8d5e5910822 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Tue, 18 Oct 2022 10:48:32 +0800 Subject: [PATCH 12/15] fix: fixed failing tests --- src/Chapter1.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 4c08e59a..3d718fd5 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -557,7 +557,8 @@ mid :: Int -> Int -> Int -> Int mid x y z | (x > y && x < z) || (x < y && x > z) = x | (y > x && y < z) || (y < x && y > z) = y - | otherwise = z + | (z > x && z < y) || (z < x && z > y) = z + | otherwise = if x == y then x else z {- | =⚔️= Task 8 From 7f4a275b1a193749a6dbc90d4eb31b1e1e3d413b Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sun, 23 Oct 2022 01:22:08 +0800 Subject: [PATCH 13/15] chore: completed Chapter 2 --- src/Chapter2.hs | 90 ++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/src/Chapter2.hs b/src/Chapter2.hs index f7c02ce2..1d89e3d4 100644 --- a/src/Chapter2.hs +++ b/src/Chapter2.hs @@ -136,43 +136,43 @@ 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,31 +186,31 @@ 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 @@ -336,7 +336,9 @@ from it! ghci> :l src/Chapter2.hs -} subList :: Int -> Int -> [a] -> [a] -subList = error "subList: Not implemented!" +subList start end list + | start < 0 || end < 0 || end < start = [] + | otherwise = drop start (take (end + 1) list) {- | =⚔️= Task 4 @@ -348,8 +350,8 @@ Implement a function that returns only the first half of a given list. >>> firstHalf "bca" "b" -} --- PUT THE FUNCTION TYPE IN HERE -firstHalf l = error "firstHalf: Not implemented!" +firstHalf :: [a] -> [a] +firstHalf l = take (div (length l) 2) l {- | @@ -501,7 +503,9 @@ True >>> isThird42 [42, 42, 0, 42] False -} -isThird42 = error "isThird42: Not implemented!" +isThird42 :: [Int] -> Bool +isThird42 (_:_:42:_) = True +isThird42 _ = False {- | @@ -606,7 +610,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 +626,10 @@ 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) = x : takeEven xs +takeEven (x:xs) = x : takeEven xs {- | =🛡= Higher-order functions @@ -728,7 +736,7 @@ value of the element itself 🕯 HINT: Use combination of 'map' and 'replicate' -} smartReplicate :: [Int] -> [Int] -smartReplicate l = error "smartReplicate: Not implemented!" +smartReplicate l = concat (map (\x -> replicate x x) l) {- | =⚔️= Task 9 @@ -741,7 +749,8 @@ 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 :: (Foldable t, Eq a) => a -> [t a] -> [t a] +contains n l = filter (elem n ) l {- | @@ -781,12 +790,14 @@ 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 :: [Int] -> [Int] -> [Int] pairMul xs ys = zipWith (*) xs ys {- | @@ -842,7 +853,11 @@ list. 🕯 HINT: Use the 'cycle' function -} -rotate = error "rotate: Not implemented!" +rotate :: Int -> [a] -> [a] +rotate n l + | n < 0 = [] + | n == 0 = l + | otherwise = take (length l) (drop (n `mod` (length l)) (cycle l)) {- | =💣= Task 12* @@ -858,7 +873,12 @@ 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 l = go l [] + where + go :: [a] -> [a] -> [a] + go [] z = z + go (x:xs) z = go xs (x:z) {- From bf665a62905474c58d8baea9e0688c3fc052df57 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sun, 23 Oct 2022 01:29:43 +0800 Subject: [PATCH 14/15] fix: fixed failing doctest job --- src/Chapter2.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter2.hs b/src/Chapter2.hs index fb1f54be..3ed3d238 100644 --- a/src/Chapter2.hs +++ b/src/Chapter2.hs @@ -140,7 +140,7 @@ List of booleans: String is a list of characters: >>> :t "some string" -"some string" :: String +"some string" :: [Char] Empty list: >>> :t [] From b15d6b165f3200af67f0f722f77f2ee1bff59a26 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sat, 29 Oct 2022 00:54:46 +0800 Subject: [PATCH 15/15] chore: completed Chapter 3 --- src/Chapter3.hs | 276 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 264 insertions(+), 12 deletions(-) diff --git a/src/Chapter3.hs b/src/Chapter3.hs index 06181106..6fb374b6 100644 --- a/src/Chapter3.hs +++ b/src/Chapter3.hs @@ -344,6 +344,14 @@ 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 + { title :: String + , author :: String + , pubYear :: Int + , pubName :: String + , isbn :: Int + } + {- | =⚔️= Task 2 @@ -376,6 +384,42 @@ after the fight. The battle has the following possible outcomes: -} +data Knight = MkKnight + { knightName :: String + , knightHealth :: Int + , knightAttack :: Int + , knightGold :: Int + } deriving(Show) + +data Monster = MkMonster + { monsterName :: String + , monsterHealth :: Int + , monsterAttack :: Int + , monsterGold :: Int + } deriving(Show) + +beowulf :: Knight +beowulf = MkKnight + { knightName = "Beowulf" + , knightAttack = 110 + , knightHealth = 100 + , knightGold = 20 + } + +grendel :: Monster +grendel = MkMonster + { monsterName = "Grendel" + , monsterAttack = 120 + , monsterHealth = 100 + , monsterGold = 20 + } + +fight :: Knight -> Monster -> Int +fight k m + | monsterHealth m < knightAttack k = (knightGold k + monsterGold m) + | knightHealth k < monsterAttack m = -1 + | otherwise = knightGold k + {- | =🛡= Sum types @@ -462,6 +506,8 @@ 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 Meal = Breakfast | Brunch | Elevenses | Lunch | Merienda | Tea | Supper | Dinner + {- | =⚔️= Task 4 @@ -482,6 +528,62 @@ After defining the city, implement the following functions: and at least 10 living __people__ inside in all houses of the city in total. -} +data City = MkCity + { cityCastle :: String + , cityWall :: Bool + , cityBuilding :: Building + , cityHouses :: [House] + } deriving (Show) + +data Building = Church | Library deriving (Show) + +data House = One | Two | Three | Four deriving (Show) + +testCity :: City +testCity = MkCity + { cityCastle = "" + , cityWall = False + , cityBuilding = Church + , cityHouses = [] + } + +buildCastle :: String -> City -> City +buildCastle castleName city = city { cityCastle = castleName } + +hasCastle :: City -> Bool +hasCastle city = case cityCastle city of + "" -> False + _ -> True + +buildHouse :: House -> City -> City +buildHouse house city = city { cityHouses = cityHouses city ++ [house] } + +countPeople :: House -> Int +countPeople house = case house of + One -> 1 + Two -> 2 + Three -> 3 + Four -> 4 + +buildWalls :: City -> City +buildWalls city = + if (sum (map countPeople (cityHouses city)) >= 10) && (hasCastle city) + then city { cityWall = True } + else city { cityWall = False } + +-- Functions to verify if values are correct +showCastle :: City -> IO () +showCastle city = print (cityCastle city) + +showWall :: City -> IO () +showWall city = print (cityWall city) + +showBuilding :: City -> IO () +showBuilding city = print (cityBuilding city) + +showHouses :: City -> IO () +showHouses city = print (cityHouses city) + {- =🛡= Newtypes @@ -562,22 +664,30 @@ introducing extra newtypes. 🕯 HINT: if you complete this task properly, you don't need to change the implementation of the "hitPlayer" function at all! -} +newtype Health = Health Int +newtype Armor = Armor Int +newtype Attack = Attack Int +newtype Dexterity = Dexterity Int +newtype Strength = Strength Int +newtype Damage = Damage Int +newtype Defense = Defense Int + data Player = Player - { playerHealth :: Int - , playerArmor :: Int - , playerAttack :: Int - , playerDexterity :: Int - , playerStrength :: Int - } + { playerHealth :: Health + , playerArmor :: Armor + , playerAttack :: Attack + , playerDexterity :: Dexterity + , playerStrength :: Strength + } -calculatePlayerDamage :: Int -> Int -> Int -calculatePlayerDamage attack strength = attack + strength +calculatePlayerDamage :: Attack -> Strength -> Damage +calculatePlayerDamage (Attack attack) (Strength strength) = Damage (attack + strength) -calculatePlayerDefense :: Int -> Int -> Int -calculatePlayerDefense armor dexterity = armor * dexterity +calculatePlayerDefense :: Armor -> Dexterity -> Defense +calculatePlayerDefense (Armor armor) (Dexterity dexterity) = Defense (armor * dexterity) -calculatePlayerHit :: Int -> Int -> Int -> Int -calculatePlayerHit damage defense health = health + defense - damage +calculatePlayerHit :: Damage -> Defense -> Health -> Health +calculatePlayerHit (Damage damage) (Defense defense) (Health health) = Health (health + defense - damage) -- The second player hits first player and the new first player is returned hitPlayer :: Player -> Player -> Player @@ -755,6 +865,33 @@ parametrise data types in places where values can be of any general type. maybe-treasure ;) -} +data Lair a x = Lair + { dragon :: Dragon a + , treasure :: TreasureChest x + } deriving (Show) + +data Dragon magicPower = Dragon magicPower deriving (Show) + +data TreasureChest x = TreasureChest + { treasureChestGold :: Int + , treasureChestLoot :: x + } deriving (Show) + +mkDragon :: a -> Dragon a +mkDragon a = Dragon a + +mkTreasureChest :: x -> TreasureChest x +mkTreasureChest treasure = TreasureChest + { treasureChestGold = 100 + , treasureChestLoot = treasure + } + +mkLair :: Dragon a -> TreasureChest x -> Lair a x +mkLair dragon chest = Lair + { dragon = dragon + , treasure = chest + } + {- =🛡= Typeclasses @@ -912,6 +1049,33 @@ Implement instances of "Append" for the following types: class Append a where append :: a -> a -> a +newtype Gold = Gold Int + deriving (Show) + +instance Append Int where + append :: Int -> Int -> Int + append a b = a + b + +instance Append Gold where + append :: Gold -> Gold -> Gold + append (Gold a) (Gold b) = Gold (a + b) + +instance (Append a) => Append [a] where + append :: [a] -> [a] -> [a] + append a b = a ++ b + +instance (Append a) => Append (Maybe a) where + append :: Maybe a -> Maybe a -> Maybe a + append (Just a) (Just b) = Just (append a b) + append (Just a) _ = Just a + append _ (Just b) = Just b + append _ _ = Nothing + +appendMaybe :: Append a => Maybe a -> Maybe a -> Maybe a +appendMaybe a b = append a b + +a = Just (Gold (25 :: Int)) +b = Just (Gold (75 :: Int)) {- =🛡= Standard Typeclasses and Deriving @@ -973,6 +1137,37 @@ implement the following functions: 🕯 HINT: to implement this task, derive some standard typeclasses -} +data Days = Saturday | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday + deriving (Show, Eq, Ord) + +instance Enum Days where + toEnum :: Int -> Days + toEnum 0 = Saturday + toEnum 1 = Sunday + toEnum 2 = Monday + toEnum 3 = Tuesday + toEnum 4 = Wednesday + toEnum 5 = Thursday + toEnum 6 = Friday + + fromEnum :: Days -> Int + fromEnum Saturday = 0 + fromEnum Sunday = 1 + fromEnum Monday = 2 + fromEnum Tuesday = 3 + fromEnum Wednesday = 4 + fromEnum Thursday = 5 + fromEnum Friday = 6 + +isWeekend :: Days -> Bool +isWeekend days = days == Saturday || days == Sunday + +nextDay :: Days -> Days +nextDay day = toEnum $ ((fromEnum day) + 1) `mod` 7 + +daysToParty :: Days -> Int +daysToParty day = fromEnum (Friday :: Days) - fromEnum day + {- =💣= Task 9* @@ -1008,6 +1203,63 @@ Implement data types and typeclasses, describing such a battle between two contestants, and write a function that decides the outcome of a fight! -} +data KnightActions = KnightAttacks | DrinksPotion Int | CastsSpell Int + deriving (Show, Eq) + +data MonsterActions = MonsterAttacks | RunsAway + deriving (Show, Eq) + +data BattleKnight = BattleKnight + { bkHealth :: Int + , bkAttack :: Int + , bkDefence :: Int + } deriving (Show, Eq) + +data BattleMonster = BattleMonster + { bmHealth :: Int + , bmAttack :: Int + } deriving (Show, Eq) + +class CommonProperties a b where + knightAttacks :: a -> b -> b + monsterAttacks :: a -> b -> a + +instance CommonProperties BattleKnight BattleMonster where + knightAttacks :: BattleKnight -> BattleMonster -> BattleMonster + knightAttacks (BattleKnight kH kA kD ) (BattleMonster mH mA) = BattleMonster (mH - kA) mA + + monsterAttacks :: BattleKnight -> BattleMonster -> BattleKnight + monsterAttacks (BattleKnight kH kA kD ) (BattleMonster mH mA) = BattleKnight (kH + kD - mA) kA kD + +knightAction :: BattleKnight -> BattleMonster -> KnightActions -> Either BattleKnight BattleMonster +knightAction (BattleKnight kH kA kD ) (BattleMonster mH mA) k = case k of + KnightAttacks -> Right $ knightAttacks (BattleKnight kH kA kD ) (BattleMonster mH mA) + DrinksPotion p -> Left $ BattleKnight (kH + p) kA kD + CastsSpell s -> Left $ BattleKnight kH kA (kD + s) + +monsterAction :: BattleKnight -> BattleMonster -> MonsterActions -> BattleKnight +monsterAction (BattleKnight kH kA kD ) (BattleMonster mH mA) m = case m of + MonsterAttacks -> monsterAttacks (BattleKnight kH kA kD ) (BattleMonster mH mA) + RunsAway -> BattleKnight kH kA kD + +bossFight :: BattleKnight -> BattleMonster -> [KnightActions] -> [MonsterActions] -> Either BattleKnight BattleMonster +bossFight (BattleKnight kH kA kD ) (BattleMonster mH mA) (k : []) (m : []) = + Left $ case knightAction (BattleKnight kH kA kD ) (BattleMonster mH mA) k of + Left (BattleKnight health attack defence) -> monsterAction (BattleKnight health attack defence) (BattleMonster mH mA) m + Right (BattleMonster health attack) -> monsterAction (BattleKnight kH kA kD) (BattleMonster health attack) m + +morning :: BattleKnight +morning = BattleKnight + { bkHealth = 100 + , bkAttack = 25 + , bkDefence = 10 + } + +poke :: BattleMonster +poke = BattleMonster + { bmHealth = 120 + , bmAttack = 30 + } {- You did it! Now it is time to open pull request with your changes