-- | Working with List 2 -- Examples to illustrate list comprehensions and recursive list functions -- Introduction Functional Programming 2019. import Prelude hiding (head,tail,last,init,reverse) import Data.Char import Test.QuickCheck {- This started as a skeleton, the definitions were filled in during the lecture. -} -------------------------------------------------------------------------------- -- * List comprehensions for operating on *all* elemenents in a list -- | sumSquares n gives the sum of the squares of the numbers from 1 to n sumSquares :: Int -> Int sumSquares n = sum [ x^2 | x<-[1..n]] -- | Change each character to upper case allCAPS :: String -> String allCAPS s = [toUpper c | c<-s] -- | takeWords n s returns the first n words of s takeWords :: Int -> String -> String takeWords n s = unwords (take n (words s)) -- | capitalize s capitalizes all words in s capitalize :: String -> String capitalize s = unwords [ cap w | w <- words s] where cap (c:s) = toUpper c:s -------------------------------------------------------------------------------- -- * List comprehensions for operating on *some* elements in a list (filtering) -- | keepPositives as delete all negative numbers from as keepPositives :: [Int] -> [Int] keepPositives as = [ a | a<-as, a>0 ] -- | factors n lists the (positive) factors of n factors :: Int -> [Int] factors n = [ x | x<-[1..n], n `mod` x == 0] -- | isPrime n checks is n is a (positive) prime number isPrime :: Int -> Bool isPrime n = factors n == [1,n] -------------------------------------------------------------------------------- -- * List comprehensions with multiple list generators -- | A chess board has 8*8 squares, columns A to H, rows 1 to 8. chessSquares :: [String] chessSquares = [[col,row] | col<-['A'..'H'], row<-['1'..'8']] -- | The squares ordered by row chessSquares' :: [String] chessSquares' = [[col,row] | row<-['1'..'8'], col<-['A'..'H']] -- | dices n returns the ways that a pair of dices can result in the sum n dices :: Int -> [(Int,Int)] dices n = [(x,y) | x<-[1..6], y<-[1..6], x+y==n] -- | check_max n checks that the max function is correct for all arguments -- from 0 to n check_max :: Int -> Bool check_max n = and [prop_max x y | x<-[0..n], y<-[0..n]] -- Property: max x y returns the larger of x and y prop_max x y = if x>y then max x y == x else max x y == y -- | closestPoints ps gives the distance between the closest (non-equal) -- points in the list ps --closestPoints :: [(Double,Double)] -> Double --closestPoints ps = distance (x1,y1) (x2,y2) = sqrt ((x1-x2)^2 + (y1-y2)^2) points :: [(Double,Double)] points = [(0.0,0.0), (0,4.0), (3.0,4.0)] -- | translate a sentense to the "pirate language" (rövarspråket) -- Example: toPirateLang "bar" == "bobaror" toPirateLang :: String -> String toPirateLang s = [ p | c<-s, p<-pirate c] where pirate c | isConsonant c = [c,'o',c] | otherwise = [c] isConsonant c = elem (toLower c) "bcdfghjklmnpqrstvwxz" -- | Finding pythagorean triangles, -- e.g. integers a, b, c such that a^2 + b^2 = c^2 --pythagorean :: Int -> [(Int,Int,Int)] --pythagorean n = -------------------------------------------------------------------------------- -- * More functions on lists (including some recursive functions) -- ** Working near the front of a list is quick and easy -- | head [1,2,3] = 1 head (x:xs) = x -- | tail [1,2,3] = [2,3] tail (x:xs) = xs -- ** Working near the back of a list require more work -- | last [1,2,3] = 3 last [x] = x last (x:xs) = last xs -- | init [1,2,3] = [1,2] init [x] = [] init (x:xs) = x:init xs -- | append xs ys = xs++ys, example: append [1,2] [3,4] = [1,2,3,4] append :: [a] -> [a] -> [a] append [] ys = ys append (x:xs) ys = x : append xs ys {- Example append [1,2] [3,4] append (1 : 2 : []) [3,4] ... -} -- | reverse (same as last time) reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] {- Example reverse [1,2,3] reverse (1 : 2 : 3 : []) reverse (2 : 3 : []) ++ [1] (reverse (3 : []) ++ [2]) ++ [1] ((reverse [] ++ [3]) ++ [2]) ++ [1] (([] ++ [3]) ++ [2]) ++ [1] -- 1 step ([3] ++ [2]) ++ [1] -- 2 steps [3,2] ++ [1] -- 3 steps [3,2,1] -} -- | The number of steps to reverse a list of length n steps_reverse n = n + sum [1..n] steps_reverse' n = n + (n^2 + n) `div` 2 prop_steps_reverse (NonNegative n) = steps_reverse n == steps_reverse' n -- | Faster reverse rev :: [a] -> [a] rev xs = revOnto xs [] -- | revOnto xs ys = reverse xs ++ ys -- move elements from the front of one list to the front of another list revOnto :: [a] -> [a] -> [a] revOnto [] ys = ys revOnto (x:xs) ys = revOnto xs (x:ys) {- Example: rev [6,7,8] ... -} --prop_rev :: [Int] -> Bool --prop_rev xs =