Computer Graphics in Haskell
January 01, 0001Welcome
- http://savanni.luminescent-dreams.com/static/presentations/haskell-graphics.html
- Software Engineer at EnergyCurb
- Twitter: @savannidgerinel
- savanni@luminescent-dreams.com
- Code witch, photographer, cyclist, agender, feminist, radical queer, general geek
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)
] )