Luminescent Dreams

Computer Graphics in Haskell

January 01, 0001

Welcome

Functions

circleArea :: Float -> Float
circleArea r = pi * r ^ 2

rectangleArea :: Float -> Float -> Float
rectangleArea l w = l * w

triangleArea :: Float -> Float -> Float
triangleArea h b = h * b / 2

totalCirclesArea :: [Float] -> Float
totalCirclesArea rs = sum (map circleArea rs)

Function Structure

functionName :: TypeParam1 -> TypeParam2 -> ... -> TypeResult
functionName param1 param2 ... =

Functions

pi :: Float

Functions

not :: Bool -> Bool

not is a function which takes a single parameter (a Boolean) and returns a result (another Boolean).

Functions

(++) :: String -> String -> String

++ is a function which takes one parameter (a String) and returns a new function that takes a single parameter (also a String) and returns a result.

Functions

(++) :: String -> String -> String

> :t (++) "a"
(++) "a" :: String -> String

Functions

(++) :: String -> String -> String

> :t (++) "a" "b"
(++) "a" "b" :: String
> (++) "a" "b"
"ab"

Functions

(++) :: String -> String -> String

> :t (++) "a" "b"
(++) "a" "b" :: String
> (++) "a" "b"
"ab"
> "a" ++ "b"
"ab"

Polymorphism

(++) :: [a] -> [a] -> [a]

++ is a function which takes one parameter (a list of anything) and returns a new function that takes a single parameter (also a list, but of the same thing) and returns a result. ++ works on the list structure and cares nothing for the data contained in the list.

Partial Application and more Polymorphism

map :: (a -> b) -> [a] -> [b]

Map is a function which takes one parameter (itself a function) and returns a new function that takes a single parameter and returns a result.

Partial Application and more Polymorphism

map :: (a -> b) -> [a] -> [b]

> :t map not
map not :: [Bool] -> [Bool]

Partial Application and more Polymorphism

map :: (a -> b) -> [a] -> [b]

> :t map not
map not :: [Bool] -> [Bool]

> :t map not [True, True, False]
map not [True, True, False] :: [Bool]
> map not [True, True, False]
[False,False,True]

Type Constraints

show :: Show a => a -> String

> show 15
"15"

show is a function that takes a value, which must implement the Show interface, and returns a String.

Type Constraints

show :: Show a => a -> String

class Show a where
  show :: a -> String

show is a function that takes a value, which must implement the Show interface, and returns a String.

Building polymorphism

circleArea :: Float -> Float
circleArea r = pi * r ^ 2

rectangleArea :: Float -> Float -> Float
rectangleArea l w = l * w

triangleArea :: Float -> Float -> Float
triangleArea h b = h * b / 2

totalCirclesArea :: [Float] -> Float
totalCirclesArea rs = sum (map circleArea rs)

Building polymorphism

area :: ??? -> Float

totalArea :: [???] -> Float
totalArea shapes = sum (map area shapes)

Defining a data type

  • Int
  • Float
  • String

Defining a data type

data Shape = ...
           deriving (Show)

Defining a data type

data Shape = Circle
           deriving (Show)

Shapes> let a = Circle
Shapes> a
Circle
Shapes> :t a
a :: Shape
Shapes> :t Circle
Circle :: Shape

Add a radius to the Circle

data Shape = Circle Float
           deriving (Show)

Shapes> :t Circle
Circle :: Float -> Shape
Shapes> let a = Circle 15
Shapes> a
Circle
Shapes> :t a
a :: Shape

Python Equivalent

class Shape:
  def __init__ (self, name, *args):
    self.shape = name
    self.args = args

  @classmethod
  def Circle (cls, radius):
    return cls("Circle", radius)

Add a few more shapes

data Shape = Circle Float
           | Rectangle Float Float
           | Triangle Float Float
           deriving (Show)

Shapes> :t Circle 15
Shape
Shapes> :t Rectangle 15.0 16.0
Shape

Python Equivalent

class Shape:
  def __init__ (self, name, *args):
    self.shape = name
    self.args = args

  @classmethod
  def Circle (self, radius):
    return cls("Circle", radius)

  @classmethod
  def Rectangle (self, length, width):
    return cls("Rectangle", length, width)

  @classmethod
  def Triangle (self, height, base):
    return cls("Triangle", height, base)

Destructuring

area :: Shape -> Float
area (Circle ...) = ...
area (Rectangle ...) = ...
area (Triangle ...) = ...

Destructuring

area :: Shape -> Float
area (Circle r) = pi * r ^ 2
area (Rectangle l w) = l * w
area (Triangle b h) = b * h / 2

Destructuring

area :: Shape -> Float
area (Circle r) = pi * r ^ 2
area (Rectangle l w) = l * w
area (Triangle b h) = b * h / 2

totalArea :: [Shape] -> Float
totalArea shapes = sum (map area shapes)

Seen in action

*Shapes> map area [Circle 1, Rectangle 1 1, Triangle 1 1]
[3.1415927,1.0,0.5]
*Shapes> map area [Circle 15, Rectangle 14 20, Triangle 15 16]
[706.85834,280.0,120.0]

Let’s switch to graphics

Gloss

display :: Display -> Color -> Picture -> IO ()

Gloss Pictures

data Picture = Circle Float
             | Polygon Path
             | Blank

display (InWindow "Women Who Code" (200, 200) (10, 10)) black (Circle 80)

Gloss Pictures

data Picture = Circle Float
             | Polygon Path
             | Blank
             | Color Color Picture

display (InWindow "Women Who Code" (200, 200) (10, 10)) black (Color white (Circle 80))

Gloss Pictures

data Picture = Circle Float
             | Polygon Path
             | Blank
             | Color Color Picture
             | Pictures [Picture]

display (InWindow "Women Who Code" (200, 200) (10, 10))
        black
        (Pictures [ Color white (Circle 80)
                  , Color blue (Circle 40)
                  ] )

Gloss Pictures

data Picture = Circle Float
             | Polygon Path
             | Blank
             | Color Color Picture
             | Pictures [Picture]
             | Translate Float Float Picture
             | Rotate Float Picture
             | Scale Float Float Picture

display (InWindow "Women Who Code" (200, 200) (10, 10))
        black
        (Pictures [ Color white (Translate 15 0 (Circle 80))
                  , Color blue (Circle 40)
                  ] )

References