-- Exercise set 2: -- * Guards -- * Lists -- * Maybe -- * Either -- -- Functions you will need: -- * head, tail -- * take, drop -- * length -- * null module Set2a where import Mooc.Todo -- Some imports you'll need. Don't add other imports :) import Data.List ------------------------------------------------------------------------------ -- Ex 1: Define the constant years, that is a list of the values 1982, -- 2004 and 2020 in this order. years :: [Int] years = [1982, 2004, 2020] ------------------------------------------------------------------------------ -- Ex 2: define the function takeFinal, which returns the n last -- elements of the given list. -- -- If the list is shorter than n, return all elements. -- -- Hint! remember the take and drop functions. -- 3 -- [12345] -- ^^^ takeFinal :: Int -> [a] -> [a] takeFinal n xs | n >= length xs = xs | otherwise = drop (length xs - n) xs ------------------------------------------------------------------------------ -- Ex 3: Update an element at a certain index in a list. More -- precisely, return a list that is identical to the given list except -- the element at index i is x. -- -- Note! indexing starts from 0 -- -- Examples: -- updateAt 0 4 [1,2,3] ==> [4,2,3] -- updateAt 2 0 [4,5,6,7] ==> [4,5,0,7] updateAt :: Int -> a -> [a] -> [a] updateAt i x xs | i >= length xs = xs | i == 0 = [x] ++ tail xs | otherwise = take i xs ++ [x] ++ drop (i+1) xs where ix = xs !! i ------------------------------------------------------------------------------ -- Ex 4: substring i j s should return the substring of s starting at -- index i and ending at (right before) index j. Indexes start from 0. -- -- Remember that strings are lists! -- -- Examples: -- substring 2 5 "abcdefgh" ==> "cde" -- substring 2 2 "abcdefgh" ==> "" -- substring 0 4 "abcdefgh" ==> "abcd" substring :: Int -> Int -> String -> String substring i j s = drop i (take j s) ------------------------------------------------------------------------------ -- Ex 5: check if a string is a palindrome. A palindrome is a string -- that is the same when read backwards. -- -- Hint! There's a really simple solution to this. Don't overthink it! -- -- Examples: -- isPalindrome "" ==> True -- isPalindrome "ABBA" ==> True -- isPalindrome "racecar" ==> True -- isPalindrome "AB" ==> False isPalindrome :: String -> Bool isPalindrome str = if str == reverse str then True else False ------------------------------------------------------------------------------ -- Ex 6: implement the function palindromify that chops a character -- off the front _and_ back of a string until the result is a -- palindrome. -- -- Examples: -- palindromify "ab" ==> "" -- palindromify "aaay" ==> "aa" -- palindromify "xabbay" ==> "abba" -- palindromify "abracacabra" ==> "acaca" palindromify :: String -> String palindromify s | s == reverse s = s | otherwise = palindromify (tail (init s)) ------------------------------------------------------------------------------ -- Ex 7: implement safe integer division, that is, a function that -- returns a Just result normally, but Nothing if the divisor is zero. -- -- Remember that integer division can be done with the div function. -- -- Examples: -- safeDiv 4 2 ==> Just 2 -- safeDiv 4 0 ==> Nothing safeDiv :: Integer -> Integer -> Maybe Integer safeDiv x y | y == 0 = Nothing | otherwise = Just(x `div` y) ------------------------------------------------------------------------------ -- Ex 8: implement a function greet that greets a person given a first -- name and possibly a last name. The last name is represented as a -- Maybe String value. -- -- Examples: -- greet "John" Nothing ==> "Hello, John!" -- greet "John" (Just "Smith") ==> "Hello, John Smith!" greet :: String -> Maybe String -> String greet first Nothing = "Hello, " ++ first ++ "!" greet first (Just last) = "Hello, " ++ first ++ " " ++ last ++ "!" ------------------------------------------------------------------------------ -- Ex 9: safe list indexing. Define a function safeIndex so that -- safeIndex xs i -- gets the element at index i in the list xs. If i is not a valid -- index, Nothing is returned. -- -- Examples: -- safeIndex [True] 1 ==> Nothing -- safeIndex [10,20,30] 0 ==> Just 10 -- safeIndex [10,20,30] 2 ==> Just 30 -- safeIndex [10,20,30] 3 ==> Nothing -- safeIndex ["a","b","c"] (-1) ==> Nothing safeIndex :: [a] -> Int -> Maybe a safeIndex xs i | i > length xs-1 || i < 0 = Nothing | otherwise = Just(xs !! i) ------------------------------------------------------------------------------ -- Ex 10: another variant of safe division. This time you should use -- Either to return a string error message. -- -- Examples: -- eitherDiv 4 2 ==> Right 2 -- eitherDiv 4 0 ==> Left "4/0" eitherDiv :: Integer -> Integer -> Either String Integer eitherDiv x y | y == 0 = Left(show x ++ "/" ++ show y) | otherwise = Right(x `div` y) ------------------------------------------------------------------------------ -- Ex 11: implement the function addEithers, which combines two values of type -- Either String Int into one like this: -- -- - If both inputs were Ints, sum the Ints -- - Otherwise, return the first argument that was not an Int -- -- Hint! Remember pattern matching -- -- Examples: -- addEithers (Right 1) (Right 2) ==> Right 3 -- addEithers (Right 1) (Left "fail") ==> Left "fail" -- addEithers (Left "boom") (Left "fail") ==> Left "boom" addEithers :: Either String Int -> Either String Int -> Either String Int addEithers (Right a) (Right b) = Right (a + b) addEithers (Left a) (Left b) = Left a addEithers (Left a) (Right b) = Left a addEithers (Right a) (Left b) = Left b