DrawingCombinators

Graphics.DrawingCombinators seems to be a very good fit for my purposes. I was just in the process of converting a game written in gloss to sdl2 to allow input from a joystick (which gloss lacks). The problem is that `sdl2`

lacks a corresponding simple abstraction for vector graphics, Picture, which gloss has.

The `Picture`

(in gloss) defines an abstract data type that allow basic shapes, transformations and colors to be composed in a simple way. You really don’t need any knowledge of OpenGL to use `gloss`

.

`DrawingCombinators`

library is also very compact (only two files) and elegantly written.

The problem is that the library is so abstract and pure that I have a really hard time to understand it. Because I want to be able to extend the library I need to understand how it works. I’m also considering using gloss abstraction with sdl2 because that is much more straight forward, but with much more code.

Still, `DrawingCombinators`

is really the essence of what I need. Actually it has two parts 2D drawing and 2D shape detection on a point and I only need the drawing part.

So here’s my attempt to understand the libraries core parts …

`DrawingCombinators`

use an `Image`

as its basic building block for 2D pictures.

```
data Image a = Image { dRender :: Renderer
, dPick :: Picker a }
```

An image is really a `Renderer`

.

`type Renderer = Affine -> Color -> IO ()`

The picker part includes the type parameter `a`

, but I will not go into that part much.

`type Picker a = R2 -> a`

So a renderer can render its image in a color transformed by an affine transformation (represented as the transformation matrix).

```
data Affine = M !R !R !R
!R !R !R
-- 0 0 1
```

An image may be composed of many images. This is done by instantiating the Monoid instance for `Image`

.

```
instance (Monoid m) => Monoid (Image m) where
mempty = pure mempty
mappend = liftA2 mappend
```

That looks simple enough!

```
pure mempty :: (Applicative f, Monoid a) => f a
mappend :: Monoid a => a -> a -> a
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 mappend :: (Applicative f, Monoid c) => f c -> f c -> f c
```

First I was very confused by the “lifting”. But monoid instance of `Image`

seems to require `Image`

to be an `Applicative`

.

This turns out to be a common instantiation of monoid. See Equational reasoning at scale for more background on this.

`mappend`

for e.g. IO () can be implemented the exact same way.

```
print "hello" :: IO ()
liftA2 mappend (print "hello") (print "world")
"hello"
"world"
mappend io1 io2 = do
a1 <- io1
a2 <- io2
return (mappend a1 a2)
OR
mappend = liftA2 mappend
```

For monads like `IO`

, `>>`

has the same meaning i.e. it composes two monads where the first is computed before the other and its results are appended.

```
(>>) :: Monad m => m a -> m b -> m b
(print "hello") (print "world")
"hello"
"world"
```

The same works for functions (`a -> b`

).

```
(+1) :: Num a => a -> a
liftA2 (+) (+2) (*3) 4
18
liftA2 (mappend) (+2) (*3) 4 :: Sum Int
Sum {getSum = 18}
```

We can always get a monoid from an applicative this way.

So, `Image`

also instantiates Applicative

```
instance Applicative Image where
pure x = Image {
dRender = (pure.pure.pure) (),
dPick = const x
}
df <*> dx = Image {
-- reversed so that things that come first go on top
dRender = (liftA2.liftA2.liftA2) mappend (dRender dx) (dRender df),
dPick = dPick df <*> dPick dx
}
}
```

What happens here? `mappend`

is lifted 3 times on the renderer!

`(<*>) :: Applicative f => f (a -> b) -> f a -> f b`

`<*>`

lifts a function inside an applicative.

First parameter is function on the result of the rendering.

```
let renderer = \a b -> print a >> print b
renderer :: (Show a, Show a1) => a -> a1 -> IO ()
```

We lifted `IO ()`

once to allow `mappend`

its outputs (effects).

Help from author Luke Palmer:

The pattern `(liftA2 . liftA2 . ...) f x y`

, with `n`

`liftA2`

s, is a semantic editor combinator style pattern, which just means to apply f to x and y nested under n applicatives.

We’re working with `Affine -> Color -> IO ()`

objects, so the `mappend`

is applied to the type 3 levels deep: `()`

.

In more detail:

```
(liftA2.liftA2.liftA2) mappend :: f (f1 (f2 c)) -> f (f1 (f2 c)) -> f (f1 (f2 c))
f ~ (Affine ->)
f1 ~ (Color ->)
f2 ~ IO
c ~ ()
```

The monoid instance used here is the trivial monoid instance on () …

But another part was still confusing. First parameter of `<*>`

is a function nested under an applicative.

So what does a function on the applicative image really mean? The previous discussion require `df`

and `dx`

to have the same type.

`dRender df , dRender dx :: Affine -> Color -> IO ()`

It turns out that because the render part of the applicative instance of image doesn’t include the type parameter `a`

we can assume this part to have the same type. So this means that appending the results of the IO operations is a perfectly valid way to handle this part.

And the other part `dPick`

does assume a `df`

to be a function nested under an applicative.

```
type Picker a = R2 -> a
dPick = dPick df <*> dPick dx
```

A similar example is the following.

```
(+) <*> (*2) $ 3
9
```

`dPick`

is a unary function just as `*2`

. `+`

is a function on a unary function i.e. a function of two parameters.

The `<*>`

creates a function where the parameter `3`

is first applied to `*2`

, and then is `3`

and the result of `2*3`

applied to `+`

i.e. `9`

.

`f <*> g = \x -> f x (g x)`

An abstract data type (ADT) is really a product type like a tuple.

```
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(u, f) <*> (v, x) = (u `mappend` v, f x)
```

In the implementation of applicative for tuple above the monoid part is just appended!