-- IB016 Seminar on Functional Programming -- Task from lecture 02 module Task02 where import qualified Data.Map.Strict as M import Test.HUnit ( Test (..), Counts, (~?=), runTestTT ) newtype MyMap k v = Mp { unMp :: M.Map k v } newtype Pair a b = Pr { unPr :: (a, b) } instance Functor (MyMap k) where fmap f (Mp insideMap) = Mp (M.map f insideMap) instance Functor (Pair a) where fmap f (Pr (x, y)) = Pr (x, f y) -- | Points with coordinates X and Y newtype Point = P { unP :: (Double, Double) } deriving (Eq, Ord, Show) -- | Canvas with named points type Canvas = M.Map Point Char -- | Example canvas with 7 points exampleCanvas :: Canvas exampleCanvas = M.fromList [ (P (0,0), 'A') , (P (1,1), 'B') , (P (2,2), 'C') , (P (3,1), 'D') , (P (4,0), 'E') , (P (5,7), 'F') , (P (-2,-1), 'G') ] -- | Returns the furthest named point from the given origin furthestFrom :: Point -- ^ Origin point -> Canvas -- ^ Canvas with points to choose from -> Maybe Char -- ^ Name of the furthest point or Nothing in case of empty canvas furthestFrom origin canvas = snd <$> (M.lookupMax $ M.mapKeys (distance origin) canvas) where distance (P (x1, y1)) (P (x2, y2)) = sqrt $ (x2-x1)^(2::Int) + (y2-y1)^(2::Int) -- | Returns all named point on the given line linePoints :: Point -- ^ First point defining the line -> Point -- ^ Second point defining the line -> Canvas -- ^ Canvas with points to choose from -> [Char] -- ^ List of named points on the line (order not specified) linePoints (P (x1, y1)) (P (x2, y2)) canvas = M.elems $ M.filterWithKey onLine canvas where onLine (P (x, y)) _ = y - y1 == slope * (x - x1) slope = (y2 - y1) / (x2 - x1) -- | Adds names to points in canvas reflected via Y axis reflectY :: Canvas -- ^ Input canvas -> Canvas -- ^ Canvas with new points reflectY canvas = M.union canvas $ M.mapKeys reflect canvas where reflect (P (x,y)) = P (-x, y) -- | Tests testSet :: Test testSet = TestLabel "Sample tests" $ TestList [ furthestFrom (P (0,0)) exampleCanvas ~?= Just 'F' , linePoints (P (0,0)) (P (5,5)) exampleCanvas ~?= "ABC" ] -- | Run tests runTests :: IO Counts runTests = runTestTT testSet