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.
Lets 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
Now 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