# To Dream of Magick

## Computer Graphics in Haskell

Savanni D'Gerinel 24 Oct, 2016

# 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)


• 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):


# 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):

@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]


# 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

## Washburn, November 2005 - September 30, 2016

Savanni D'Gerinel 1 Oct, 2016

How does one speak of the departure of a cherished friend?

My dear, loyal friend for almost eleven years passed beyond at 1:40 am on Friday, September 30th. He spent the last five hours of his life in a hospital. I had thought that I was taking him in for a dangerous but curable condition. Instead, I took him in to discover that he had a creeping condition, largely undectable, that was going to kill him.

Kylie and I were with him when he went. Kat, his original human mother, made in only a few minutes later. I had hoped he would hold on just a bit longer.

Washburn came into my life with his sister River, two brothers Simon and Malcolm, and his mother Serenity, when he was a mere five weeks old. Kat and I adopted out all of the others, but opted to keep Washburn, and then when we separated I kept him along with Ghost.

Washburn has slept with me almost every night of the last ten years. I cannot dream of counting the days in which I woke up to find him right there. Or nights in which I would be going to sleep and he would choose that moment in which I most needed to give him scritches. I would go to sleep with his purr and wake up to his purr. In his youth, he would investigate every open glass, first with his face and then with his paws. No glass was safe. Books were ruined for the sake of his love for water. I eventually foiled that by moving to using a water bottle almost exclusively. He spent years drinking from the faucet, often while I was brushing my teeth. He stopped and never really restarted, though in the last year I always got the impression he was interested.

Most of his life he was skittish around new people. In the last few years he became braver, willing to come out, investigate, and even accept pets from a new person in the house. Though he rarely had a playmate after Kat and I separated and Vladimir went with her, in the last few years he and Sapphira finally formed a bond in which they would snuggle and groom. He learned to crawl up onto my chest at night to get more pets. He would never sleep there, but sometimes he would settle down for a few minutes with his aggressive purr.

We lived out in the woods for a year, and so he is one of the few cats who has gotten to run out in the woods. He learned the joys of climbing a tree which had branches in near reach. Of running along a branch to see the world from high up. Of discovering what his claws were really good for.

In his last few minutes, I wanted more than anything to pick him up, lie down, and wrap him up next to my chest. To let him die listening to my heartbeat, as he was born listening to his feline mother’s heartbeat. Alas I did not. I feared it would distress him. I feared it would hasten the end. And perhaps, because of that, my heart is broken a little more.

Washburn made an impression upon everyone. Everyone who knew him is sad to see him go. Even his vet, who saw him once a year, called me, heartbroken.

I promised him I would be with him his entire life. Promise fulfilled. What more can a mother do?

My love, my dear friend, my child, Washburn:

I wish for you wild open fields in which to run
Forests in which to climb
Water to investigate and pet
Infinite hands to pet you
Beds in which to cuddle
And more love than even I could provide

Please forgive me for our fights
For the times I neglected you
Please remember the love I gave
The times we spent playing
The times we spent cuddled

Watch over your sisters
And be free


Maybe there is an afterlife, and maybe my love will let me visit you again.

I miss you. I will never forget you. For as long as I live, I will never let you be forgotten.

I will reserve the rest of the space for stories which I will tell as I recall them, and additional pictures as I develop them.

## Color Multipliers

Savanni D'Gerinel 29 Sep, 2014

I hacked out a small GTK utility last night. The problem, and this really only applies to Linux, is that the Sony NEX-series cameras don’t record the color temperature and green/magenta balance in the exif data. They do, however, record an RGGB line like so:

WB RGGB Levels                  : 2068 1024 1024 2160


ufraw on Linux doesn’t recognize this. With a couple of experiments I figured out what these values mean and how to translate them into something useful for ufraw. And then I reinvented it too many times and finally decided to encode it into an application.

color-temp will, given the string above, calculate out the RGB multipliers that UFraw uses for developing a raw file. I have placeholders there for color temperature and green/magenta balance (which is isomorphic to the RGB multipliers, but friendlier in some ways), but that is tricky to calculate and I haven’t succeeded at that yet.

I’m working on getting the application packaged, and when I do I’ll make a debian package available for download. Until then, just snag and build the code:

color-temp$cabal install --dependencies-only color-temp$ cabal install
anywhere\$ color-temp


And then just paste the RGGB levels (2068 1024 1024 2160) into the RGGB field.

## GTK+ Programming in Haskell

Savanni D'Gerinel 26 Sep, 2014

Earlier this evening I gave a presentation on doing GTK+ programming in Haskell. Here is the presentation for all those who could not be there.

## From a Garden Party

Savanni D'Gerinel 20 Aug, 2014


All four of these pictures are some old ones from my previous HDR work. The only thing they have in common is that they are all from a party that I went to some years ago. I wanted to get them back up, though, because I like all of them.

I really miss having a working HDR toolchain.

Dreamer, Shaper, Seeker, Maker