Topics in Advanced Computing Lesson 6: Defining Modules and Types

Last time

Breaking up

Sphere.hs:

module Geometry.Sphere
(volume,
area
) where

volume :: Float -> Float
volume radius = (4.0 / 3.0) * pi * (radius ^ 3)

area :: Float -> Float
area radius = 4 * pi * (radius ^ 2)

Cuboid.hs:

module Geometry.Cuboid
( volume
, area
) where

volume :: Float -> Float -> Float -> Float
volume a b c = rectangleArea a b * c

area :: Float -> Float -> Float -> Float
area a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2

rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b

Cube.hs:

module Geometry.Cube
( volume
, area
) where

import qualified Geometry.Cuboid as Cuboid

volume :: Float -> Float
volume side = Cuboid.volume side side side

area :: Float -> Float
area side = Cuboid.area side side side

Then:

ghci> :l Geom.Sphere Geom.Cube
[1 of 3] Compiling Geom.Cuboid ( Geom/Cuboid.hs, interpreted)
[2 of 3] Compiling Geom.Cube ( Geom/Cube.hs, interpreted)
[3 of 3] Compiling Geom.Sphere ( Geom/Sphere.hs, interpreted)
Ok, three modules loaded.
ghci> Geom.Cube.volume 2.0
8.0

Algebraic types

data MyBool = MyFalse | MyTrue

myAnd :: MyBool -> MyBool -> MyBool
myAnd MyFalse _ = MyFalse
myAnd MyTrue x = x

Unfortunately can’t print these out. What happens? Solution: add deriving Show at the end of the definition.

:k Int
Int :: *

Q: “What kind of type is Int?”
A: A concrete type (‘*’ means concrete type: takes no parameters).

What would be an example of something that might take a parameter? A Map (from Data.Map). Try checking its kind.

Definitions

Shapes

data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving Show

Value constructors are functions.

area :: Shape -> Float  
area (Circle _ _ r) = pi * r ^ 2  
area (Rectangle x1 y1 x2 y2) = (abs $ x2-x1 ) * (abs $ y2-y1)

Test out a few areas.

Better version

Introduce a Point type, that makes Circle and Rectangle easier to understand.

data Point = Point Float Float deriving Show
data Shape = Circle Point Float | Rectangle Point Point deriving Show

area :: Shape -> Float  
area (Circle _ r) = pi * r ^ 2  
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2-x1 ) * (abs $ y2-y1)

origin :: Point
origin = Point 0 0

originCircle :: Float -> Shape
originCircle = Circle origin -- "point-free" style

moveTo :: Point -> Shape -> Shape
moveTo p (Circle _ r) = Circle p r 
moveTo p@(Point x0 y0) (Rectangle (Point x1 y1) (Point x2 y2)) = Rectangle p $ Point (x0 + x2-x1) (y0 + y2 - y1)

moveTo p moves a Circle to center it at p, and moves a Rectangle so that one of its corners is at p.

Records

How would we encapsulate a type for Time? Keep track of hour, minute, and AM / PM? For a Course?

Instead of using separate fields, we can name the fields with records. Then there are auto-generated functions to retrieve those fields.

data AmPm = AM | PM deriving Show
data Time = Time { hour :: Int, minute :: Int, amPm :: AmPm } deriving Show

data Course = Course { courseName :: String, crn :: Int, day :: String, startTime :: Time, endTime :: Time} deriving Show

Then:

ghci> c = Course { courseName = “CS2”, crn = 1540, day = “MR”, startTime = Time { hour = 10, minute = 30, amPm = AM }, endTime = Time { hour = 12, minute = 10, amPm = PM } }
ghci> courseName c
“CS2”
ghci> startTime c
Time {hour = 10, minute = 30, amPm = AM}
ghci> hour $ startTime c
10