Imitating Metapost using Haskell

Brent Yorgey has released a Haskell EDSL for creating diagrams. Here is my first impression of the library, comparing it with another DSL for creating diagrams — Metapost.

lineLets start with the simplest example: drawing a straight line between two points. First the metapost code

draw (0,0)--(100,100)
withpen pencircle scaled 4bp withcolor red;

Now the same code in Haskell (this needs to be wrapped around in a function and rendered to a png or pdf, but I’ll leave that part out).

lineColor red . lineWidth 4 .
  straight $ pathFromVectors [(0,0),(100,-100)]

I like the Metapost style better (since I have been using that for ages). One minor annoyance with diagrams is that positive values of y goes downwards rather than upwards. But the main trouble for me is prefix versus infix style. For diagrams, I find the infix style much easier to read. In this post, I will try to persuade Haskell to follow that style. The transforms in the diagram package have the signature Something -> Diagram -> Diagram, while I want Diagram -> Something -> Diagram. That is easy to fix

linecolor  = flip lineColor
linewidth  = flip lineWidth
fillcolor  = flip fillColor

Now we can use

straight (pathFromVectors [(0,0),(100,-100)])
  `linewidth` 4 `linecolor` red

circleNow lets try the next simplest example: drawing a circle. Again, the metapost code first

fill fullcircle scaled 100
withcolor 0.5green ;

draw fullcircle scaled 100
withpen pencircle scaled 3 withcolor 0.5blue ;

Now using the above flipped functions, we can draw this by (there is a minor difference in metapost and diagrams. Metapost draws a circle of  a given diameter while diagrams draws a circle of a given radius).

circle 50
  `linewidth` 3 `linecolor` lightblue `fillcolor` lightgreen

Ah, much better than the metapost version.

I need to figure out two more things to be able to use the diagrams package in my publications.

  • How to define the infix equivalents of metapost’s --, ---, .., and ... in Haskell.
  • Write a Metapost/ConTeXt backend to render text using TeX.

Here is the complete code

import Graphics.Rendering.Diagrams

linecolor  = flip lineColor
linewidth  = flip lineWidth
fillcolor  = flip fillColor

example1 =
straight (pathFromVectors [(0,0),(100,-100)]) `linewidth` 4 `linecolor` red

example2 =
circle 50 `linewidth` 3 `linecolor` lightblue `fillcolor` lightgreen

main = do
renderAs PNG "line.png" (Width 100) example1
renderAs PNG "circle.png" (Width 100) example2