{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE GADTs #-} class Shape a where area :: a -> Int data Square = Square Int data Rectangle = Rec { len :: Int, width :: Int } instance Shape Square where area (Square x) = x * x instance Shape Rectangle where area r = len r * width r class (Show a, Shape a) => ShapeExt a where scale :: a -> Int -> a instance ShapeExt Square where scale (Square x) s = Square (x * s) instance ShapeExt Rectangle where scale r s = Rec { len = len r * s, width = width r * s } instance Show Square where show (Square x) = "square(" ++ show x ++ ")" instance Show Rectangle where show (Rec {len = l, width = w }) = "rectangle(" ++ show l ++ "," ++ show w ++ ")" data GeoShape = forall a. ShapeExt a => MkGeoShape a -- Equivalent to the above using GADT notation data GeoShape2 where MkGeoShape2 :: ShapeExt a => a -> GeoShape2 instance Show GeoShape where show (MkGeoShape x) = show x instance Shape GeoShape where area (MkGeoShape x) = area x instance ShapeExt GeoShape where scale (MkGeoShape x) s = MkGeoShape (scale x s) r = Rec { width = 2, len = 3 } s = Square 4 -- yields a type error -- ls = [r, s] r2 = scale r 3 s1 :: GeoShape s1 = MkGeoShape r s2 :: GeoShape s2 = MkGeoShape s shapes = [s1, s2, MkGeoShape r2] ex2 = putStrLn (unlines (["Sum of the area of"] ++ map show shapes ++ [show (sum (map area shapes))])) -- Go versus Haskell data GShape = forall a. Shape a => MkShape a instance Shape GShape where area (MkShape x) = area x -- Square <= GShape sqToGShape :: Square -> GShape sqToGShape s = MkShape s -- Rectangle <= GShape recToGShape :: Rectangle -> GShape recToGShape r = MkShape r sumArea :: GShape -> GShape -> Int sumArea x y = area x + area y sumEx = let r = Rec 1 2 s = Square 3 in sumArea (recToGShape r) (sqToGShape s) main = print $ show sumEx