The following paper was originally published in the Proceedings of the Conference on Domain-Specific Languages Santa Barbara, California, October 1997
A Special-Purpose Language for Picture-Drawing
Samuel N. Kamin and David Hyatt University of Illinois, Urbana-Champaign
For more information about USENIX Association contact: 1. Phone: 510 528-8649 2. FAX: 510 548-5738 3. Email: [email protected] 4. WWW URL:http://www.usenix.org
A Sp ecial-Purp ose Language for Picture-Drawing
y
Samuel N. Kamin David Hyatt
Computer Science Department
University of Il linois at Urbana-Champaign
Urbana, Il linois 61801
fs-kamin,[email protected]
Abstract supp orted in programming languages. This supp ort
means allowing the creation of \ rst-class" values
of eachtyp e, that is, values not sub ject to arbitrary
Special purpose languages are typical ly characterized
restrictions based on the typ e. It also means pro-
by a type of primitive data and domain-speci c oper-
viding op erations appropriate to those typ es in a
ations on this data. One approach to special purpose
concise, non-bureaucratic form.
language design is to embed the data and operations
In our view, this approach to language design is p er-
of the language within an existing functional lan-
guage. The data can be de ned using the typecon- fectly suited to the design of sp ecial-purp ose lan-
structions provided by the functional language, and guages. These languages are usually characterized
the special purpose language then inherits al l of the byatyp e of primitive data sp eci c to a problem
domain, and op erations on those data. These data
features of the more general language. In this paper
can b e incorp orated into a language having the typ e
we outline a domain-speci c language, FPIC, for
the representation of two-dimensional pictures. The constructions just mentioned. In fact, they can b e
primitive data and operations are de ned in ML. We incorp orated into an existing functional language;
outline the operations provided by the language, il- the typ e constructions will apply to the new data,
lustrate the power of the language with examples, and the entire language will then b ecome a sp ecial-
purp ose language, with its many other features in-
and discuss the design process.
cluded \for free."
The principal weakness of many sp ecial-purp ose
languages is that, b eyond a concise and natural
1 Intro duction
syntax, and ecient implementation, for the val-
ues and op erations sp eci c to the domain, over-
FPIC is a sp ecial-purp ose language for drawing sim-
arching language structure is weak. This weak-
ple pictures. It was built by de ning typ es and
ness would b e very signi cantly mitigated if sp ecial-
functions in the functional language Standard ML
purp ose languages were routinely designed|or at
[6]. This metho d of construction is easy and results
least prototyp ed|in the waywehave outlined.
in a language with many useful features. In addi-
This pap er is a case study of the design of FPIC ac-
tion to b eing concise for small examples, FPIC is
cording to this philosophy.We describ e the pro cess
powerful enough to allow the programming of large
by whichwe decided what the primitive data were
programs and program libraries, an area in which
and how they should b ehave, then describ e the lan-
many sp ecial-purp ose languages are weak.
guage itself with numerous examples. Our emphasis
Functional programming has b een characterized
throughout is on the advantages obtained byhaving
in manyways. Our view is that it repre-
the functional language sup erstructure of Standard
sents an approach to language design. This ap-
ML as part of FPIC.
proach holds that some mathematical constructs|
pro ducts, functions, disjoint unions, and others|
are fundamental in computing and should b e well
Partially supp orted by NSF Grant CCR 96{19655.
y
Current address: Netscap e Communications Corp.,
Mountain View, CA, hyatt@netscap e.com.
2 Simple FPIC Examples
PIC [4] is a language for drawing simple pictures,
such as trees and blo ck diagrams. It has primi-
tives for drawing b oxes, circles, and other shap es,
val nose = dtriangle;
with or without lab els, and for drawing lines and
circle 2.5
arrows b etween them. It also has a facility for nam-
seq nose at 2.0,2.0
ing p oints on pictures, to b e used, for example, as
seq nose rotate ~90.0 scale 0.7 at 1.2,2.7
the endp oints of lines and arrows. These constructs seq nose rotate 90.0 scale 0.7 at 3.1,2.7
seq doval scaleXY 0.5,0.3 at 1.7,0.7;
are provided in a concise syntax, with a simple lan-
guage structure including lo ops added on.
The seq op eration simply places pictures on top of
FPIC was inspired by PIC. Our goal was to demon-
one another, without moving them either rightor
strate that we could b ene t by following the lan-
down. The expression pic at point draws the picture
guage design philosophy outlined in the intro duc-
pic with its reference p oint the lower-left corner at
tion. That is, by using essentially the same primi-
point.
tive data typ es and op erations as in PIC, but em-
An imp ortant feature of PIC, whichwehave
b edding them in a functional language, we could
obtain a far more p owerful language than PIC and adopted in FPIC, is the ability to name p oints in
do so at a far lower cost than if we had built the a picture and subsequently refer to them. The com-
language from scratch. pass p oints|s for south, ne for northeast, and so
on, plus c for center|are automatically de ned for
In this section, we present a few examples to show
every picture. This allows us to eliminate some of
the principal primitive op erations of FPIC, making
the guesswork in the previous example:
only minimal use of the programming features of
Standard ML. Section 5 gives many more examples,
emphasizing the utility of the features of ML in com-
val face = circle 2.5;
bination with the FPIC primitives.
val facecenter = face pt "c";
val lefteye = nose rotate ~90.0 scale 0.7;
The most basic primitives are those for drawing sim-
val righteye = nose rotate 90.0 scale 0.7;
1
val mouth = doval scaleXY 0.5,0.3;
ple shap es and placing them next to one another:
face seq nose centeredAt facecenter
seq lefteye centeredAt facecenter -- 1.0,~0.7
seq righteye centeredAt facecenter ++ 1.0,0.7
seq mouth centeredAt facecenter -- 0.0,1.5;
Named p oints can b e added to a picture. A third
Hello!
way to pro duce the same \pumpkin face" is to draw
the face and name the lo cations of the facial fea-
box 1.0 2.0 hseq circle 1.5 vseq
tures:
label "\\Huge Hello!" oval 2.0 1.0;
val face =
hseq and vseq represent the op erations of plac-
let val f = circle 2.5
ing pictures next to one another, either horizontally
val facecenter=fpt"c"
or vertically. Note that backslashes inside quotes
in namePts f
must b e doubled.
["nosepos", facecenter,
"lefteyepos", facecenter -- 0.9,~0.8,
Pictures can b e moved and otherwise transformed in
"righteyepos", facecenter ++ 0.9,0.8,
"mouthpos", facecenter -- 0.0,1.5]
various ways. In this example, we use ML's name
end;
de nition facility in the rst line. dtriangle is a
face seq nose centeredAt face pt "nosepos"
\default triangle;" similarly for doval and dcircle
seq lefteye centeredAt face pt "lefteyepos"
and dbox later in the pap er.
seq righteye centeredAt face pt "righteyepos"
seq mouth centeredAt face pt "mouthpos";
1
App endix A gives a concise overview of ML syntax. Ap-
p endix B lists all the FPIC primitives used in the examples in
Pictures can b e named as well as p oints. This is
this pap er, indicating the typ es of their arguments, whether
or not they are in x, and what they return. useful when a numberofpoints on a picture may
b e of interest. For example, cell is a \cons cell" of PIC to help answer what we consider the most
consisting of twoboxes vertically stacked; for future crucial question in the design pro cess: what do es
reference, the individual b oxes are named car and each piece of syntax mean? In ordinary program-
cdr, resp ectively: ming terms, syntactic phrases have some intuitive
op erational meaning; \circle 2.0" means \drawa
circle with radius 2.0." A lesson from denotational
semantics is that phrases can b e given precise mean-
ings as values of well-de ned sets. It is this notion of
\meaning" that we found useful in designing FPIC.
We wish to give the reader some idea of the thought
pro cess wewent through.
val cell = namePic dbox "car"
We will call the set in which the meaning of \circle
vseq namePic dbox "cdr";
2.0" resides Picture. The question is, what exactly
is in this set? What is a picture? The most obvious
In addition to optionally b eing named, subpictures
answer is that it is some concrete representation of
are automatically numb ered. p nthpic i is the ith
a picture, for example, an array of pixels or a list
subpicture in p.
of drawing commands. The precise representation
do es not matter to us, so we will just give the rep-
Finally, another imp ortant feature of PIC and FPIC
resentation the generic name BitMap. So, our rst
is the ability to draw lines and arrows. In this pic-
idea is to say
ture, two cells are drawn with a curved arrow from
the cdr of the rst to the car of the second:
Picture = BitMap
However, a closer lo ok at PIC tells us that this can't
b e quite right. In PIC, one can write, for example,
let val cells = namePic cell "left" hseq
box; box
hspace 1.0 hseq
namePic cell "right"
val source = cells pic "left" pic "cdr" pt "c"
meaning to draw one b ox next to another. We
val target = cells pic "right" pic "car" pt "w"
would write this as dbox hseq dbox. If eachbox
in cells seq bezier source
source ++ 1.0,0.0
is a Picture, and a Picture is just a bitmap, then
target -- 1.0,0.0
these twoboxes would represent the same bitmap,
target
whichwould mean precisely the same pixels drawn
withArrowStyle "->"
at the same lo cation!
end;
We should instead say that a Picture is the capability
to draw a bitmap, given a lo cation at which to draw
it; in other words, it is a function from lo cations to
3 How to design a sp ecial-purp ose
drawing commands:
language
Picture = Location ! BitMap
Muchaswe try not to, we often design a new lan-
guage by thinking in terms of the syntax wewould
This is close, but wehave also to deal with the pic-
likeittohave. For sp ecial-purp ose languages, this
ture that we write from now on, we use FPIC syn-
generally means concentrating on the syntax of the
tax to avoid confusion:
domain-sp eci c data and op erations.
In our view, thinking ab out the desired concrete
dbox scale 5.0
syntax of the new language is not at all a bad place
to b egin the design pro cess, as long as that step is
understo o d in its prop er relation to the overall lan- Again, the bitmap cannot b e determined from the
guage design. In designing FPIC, we had an existing value of dbox,even after knowing its lo cation. We
language, PIC, to start from. We used the syntax might try
Picture = Location ! ScaleFactor ! BitMap 4 The FPIC User's Manual
Since FPIC includes Standard ML, the manual is
which is basically correct, but we also need to deal
either very long or very short, dep ending up on how
with color, line width, and a host of other ways in
you lo ok at it. In any case, FPIC consists of ab out
which the simple bitmap might b e altered.
160 functions, amounting to ab out 1200 lines of ML
From this p oint of view, the value of dbox is just
co de. In App endix B, we list all the FPIC primitives
the barest indication of what will actually showup
that are used in the examples in this pap er.
on the printed page. We represent this by de ning
Picture = GraphicsContext ! BitMap
5 FPIC Examples
where GraphicsContext contains information ab out The examples of this section showhow the features
any linear transformations that mayhave b een ap- of Standard ML, when combined with the primitives
plied to the picture, as well as color, ll style, line of FPIC, create a p owerful language for constructing
2
width, and so on. pictures.
We're not quite done. We know that we can re-
In a functional language, some fancy drawings are
fer to the p oints on a picture, for example dbox pt relatively easy to do. For example, here is the \Sier-
"nw". Evidently, dbox means something more than pinski gasket" of order 3:
a bitmap. It means, in addition, a set of named
p oints, whichwe call an Environment. This brings
us to the de nition we actually use in FPIC:
Picture =GraphicsContext ! BitMap
Environment
fun sierpinski 0 = dtriangle
| sierpinski n =
let val s = sierpinski n-1 scaleWithPoint
This de nition|and it is by no means the only
0.5,0.5,0.0,0.0
one p ossible|is the most imp ortant in the design
in s hseq s seq s at width s/2.0, height s
of FPIC. Just as the domains in the denotational
end;
semantics of a language are chosen to match the
sierpinski 3;
prop erties of that language, so here the de nition
of Picture determines, more than any other single
pic scaleWithPoint s, point scales picture pic
thing, the prop erties of FPIC. Indeed, once this def-
by a factor s while keeping point xed.
inition is made|along with the precise de nitions
However, of more interest in practice is the abil-
of GraphicsContext and Environment|the rest of
ity to create reusable pieces of pictures to ease the
the language largely falls out.
programming burden. Here is where functional pro-
When emb edding a language in a functional lan-
gramming shines.
guage like Standard ML, this typ e de nition can
also guide the implementation. Indeed, wehave
5.1 De ning lines
used exactly the typ e ab ove, written in ML as
In FPIC, a line is simply a function from two p oints
type Picture =
to a picture. Any drawing can b e parameterized by
GraphicsContext->BitMap * Environment;
a line to create a variety of e ects.
Here is a simple function to draw trees. Its argu-
as the typ e of pictures. Many of the basic op er-
ments are a picture representing the ro ot of the tree
ations on pictures, and their implementations, are
and a list of pictures representing its children.
suggested directly by this typ e de nition.
2
PostScript [1] has a similar notion of \graphics context." fun drawtree root subtrees =
let val bottom = hseqtopsplist 1.0 subtrees Moreover, we can de ne our own line-drawing func-
val top = placePt root "s"
tions. Wehave seen earlier, in the cons-cell example,
bottom pt "n" ++ 0.0,1.0
howtodraw a curvy line. We use the same idea, ex-
val rootsouth = top pt "s"
cept that here wewant our curvy line to b egin with
in group top seq bottom seq
avertical leg rather than a horizontal one. Again,
seqlist
keep in mind that a line-drawing function is just a
map fn p => line rootsouth p pt "n"
function from two p oints to a picture, nothing more
pics bottom
or less:
end;
fun curvedvline pt1 pt2 =
It draws a tree with its no des connected by lines:
bezier pt1 pt1--0.0,1.0
pt2++0.0,1.0 pt2;
let val t = drawtree dcircle [dbox, dbox]
let val t =
in drawtree dbox [t, t] end;
drawtree dcircle [dbox, dbox] curvedvline
in drawtree dbox [t, t] curvedvline end;
We can de ne a function drawTreeWithArrow that
Two more examples are a line-drawing function that
would draw arrows instead of lines, simply by re-
uses a \Manhattan geometry":
placing \line"by\arrow." However, we can do
b etter in ML, making the line-drawing function a
fun manline pt1 pt2 =
parameter. drawTree b ecomes
let val ymid = snd pt1 + snd pt2/2.0
in seqlist
fun drawtree root subtrees linefun =
[line pt1 fst pt1, ymid,
::: exactly the same, until the end :::
line fst pt1, ymid fst pt2, ymid,
seqlist
line fst pt2, ymid pt2]
map fn p => linefun rootsouth p pt "n"
end;
pics bottom
end;
Then the tree ab ovewould b e written as
let val t = drawtree dcircle [dbox, dbox] manline
in drawtree dbox [t, t] manline end;
and a function that draws short lines of whatever
kind:
let val t = drawtree dcircle [dbox, dbox] line
in drawtree dbox [t, t] line end;
fun shortline linefun pt1 pt2 =
let val diff = pt2 -- pt1;
val pt1' = pt1 ++ diff**0.25,0.25;
and we could also write
val pt2' = pt2 -- diff**0.25,0.25
in linefun pt1' pt2'
end;
let val t = drawtree dcircle [dbox, dbox] arrow in drawtree dbox [t, t] arrow end;
let val t = drawtree dcircle [dbox, dbox]
shortline arrow
in drawtree dbox [t, t] shortline arrow end;
val cseqlist = mkseqlist op cseq;
val bullseye = cseqlist map
fn rad => circle rad withFillColor
1.0/rad, 1.0/rad, 1.0/rad
let val t = drawtree dcircle [dbox, dbox]
[5.0, 4.0, 3.0, 2.0, 1.0];
shortline manline
in drawtree dbox [t, t] shortline manline end;
The function mkseqfun is provided to facilitate the
creation of new sequencing functions. Given two
5.2 De ning sequencing op erators
functions f and g from pictures to p oints, it cre-
ates the sequencing op eration that, given two pic-
The functions that put pictures together into larger
tures p and q , draws the two so that fp and gq
pictures are of key imp ortance. In FPIC, these
coincide. For example, in the tree-drawing function
are generally binary op erations with in x syntax.
presented earlier, we used the sequencing op eration
The basic sequencing op eration is seq, which sim-
hseqtopsplist, the list version of the sequencing
ply draws two pictures without prejudice; hseq and
op eration hseqtopsp. The latter sequences two pic-
vseq, among others, combine seq with some trans-
tures horizontally with their tops aligned, adding
lation of the second picture.
some space b etween them. It is not built-in, but is
de ned as follows:
Again, the ability to de ne new sequencing op era-
tions is of the greatest interest. A sequencing op-
eration is a function from a pair of pictures to a
fun hseqtopsp gap =
picture. The constructed picture should include the
mkseqfun fn p => northeast p right 1.0
northwest;
two pictures.
A simple example is cseq, which aligns the centers
The cons-cell example suggests another kind of se-
of two pictures:
quencing: sequencing with an arrow. cellseq has
as its arguments two cons cells|that is, two pic-
infix 6 cseq;
tures that are presumed to have subpictures called
fun p1 cseq p2 = p1, center p1 align
cdr and car, resp ectively|and draws them a bit
p2, center p2;
separated, with a curvy arrow. To allow more than
one cell to b e sequenced in this way, the combination
of cells is de ned to have car and cdr subpictures
itself.
infix 7 cellseq;
fun cell1 cellseq cell2 =
doval cseq doval rotate 45.0
let val c = group cell1
cseq doval rotate 90.0
hseq hspace 1.0
cseq doval rotate 135.0;
hseq group cell2
val cells = c seq curvedharrow
Given a sequence op eration seq,we often use the
c nthpic 1 pic "cdr" pt "c"
related op eration seqlist, which applies to lists of
c nthpic 3 pic "car" pt "w"
pictures. Sp eci cally:
in addNamedPics cells
["car", cells nthpic 1 pic "car",
"cdr", cells nthpic 3 pic "cdr"]
seqlist [p ;p ;:::;p ] p seq p seq ::: seq p
1 2 n 1 2 n
end;
The function mkseqlist creates the list version of a
sequencing op eration from the ordinary binary ver- For this example, wehave de ned labelledCell,
sion. which draws a cons cell with a lab el in its car:
A this information from that le. As is common with
A A
L T X utilities, this requires that L T X b e run twice
E E
when a new picture with text is added, or when the
text of an existing picture is changed, to b e sure
fun labelledCell L =
that FPIC knows the size of the text.
cell seq L centeredAt cell pic "car" pt "c";
With this feature, we can de ne a picture-framing
labelledCell text "A"
function that will correctly frame text:
cellseq
labelledCell dcircle scaleTo 0.5, 0.5
cellseq
labelledCell cell scale 0.3;
fun frame p = box width p + 0.2 height p + 0.2
cseq p;
6 Latex integration
a b f 1
0
c d
a R
A
FPIC pictures are included in L T X do cuments by
E
using the fpic command:
frame text "\\huge a"
hseq frame text "\\begin{tabular}{cc}a&b"
^ "\\\\ c & d \\end{tabular}"
\fpic{picture-name}{
hseq frame text "$\\int_{0}^{1} f$" rotate 90.0;
... FPIC speci cation ...
}
Note that the argumentto text can b e any string,
not just a string literal. The size of the text will still
The sp eci ed picture b ecomes an ordinary b oxin
b e calculated correctly:
A
LTX, so that it can b e included anywhere within
E
the do cument likeany other piece of text. For exam-
10 100 10000 100000000
box oval
ple, this and this are placed
hseqlist
A
map fn i => frame text Int.toString pow 10 i
in-line. Notice that L T X knows their sizes and
E
[1, 2, 4, 8];
creates the right amount of horizontal and vertical
space for them.
The other side of this coin is the inclusion of T X
E
7 Packages
text within FPIC pictures. The text function turns
A
a string|interpreted as L T X input|into an FPIC
E
A
picture. AnyLT X input can b e used here, and once
E
The real p oint, of course, is that FPIC can do more.
the text function is applied it b ecomes sub ject to
That is, it is not merely a sp ecial purp ose language
the same transformations as any other piece of text:
for one typ e of picture, but is in nitely extensible
to a variety of picture-drawing domains.
b
a b
Our last example is a collection of functions to
d
a
draw pie charts. This package contains the func-
c
c d
tion pieChart, which takes a list of pairs, each con-
sisting of a p ercentage and a slice-drawing function,
let val A = text
"$\\begin{array}{cc} a & b \\\\ c & d \\end{array}$"
and draws the slices. A slice-drawing function is
in hseqsplist 0.5 [A scale 1.5, A rotate 45.0]
a function from an angle in degrees to a picture;
end;
that picture will normally b e a wedge of a circle cen-
tered at 0; 0 and starting at the given angle. The
The only diculty here is that FPIC do es not know
package contains a variety of functions for creating
how large the text will turn out to b e. We adopt
slice-drawing functions. They are shown in Figure 1.
a solution to this problem similar, in essence, to
The function slice takes a collection of arguments that used by Chailloux and Suarez in mlPicTeX [2].
A
and returns a slice-drawing function. The argu- When FPIC is rst run, it pro duces L T X co de that
E
A
ments are: an external lab el to b e drawn outside causes L T X to write the size of the text to its inter-
E
the slice; the p ercentage of the pie that this slice mediate aux le; on subsequent runs, FPIC reads
fun pieChart radius pieList =
let fun pieBuilder n [a,pfun] = pfun radius n
| pieBuilder n a,pfun::slices =
let val newangle = n+a/100.0 * 360.0
in pfun radius n seq pieBuilder newangle slices
end
in pieBuilder 0.0 pieList
end;
fun slice lab percent color =
let fun makeslice radius startAngle=
let val endAngle = startAngle + percent/100.0 * 360.0
val pieSlice = wedge radius startAngle endAngle
val filledPie = pieSlice withFillColor color
val midAngle = startAngle + endAngle/2.0
val labelDist = radius/4.0
val xPt = radius+labelDist*dcos midAngle
val yPt = radius+labelDist*dsin midAngle
val extLabel = text lab centeredAt xPt, yPt
in filledPie seq extLabel
end
in percent, makeslice
end;
fun explodeSlice percent, picfun =
percent, fn rad => fn startAngle =>
let val angleDelta = percent/100.0 * 360.0/2.0
val centerAngle = startAngle + angleDelta
val centerUnitVec = dcos centerAngle, dsin centerAngle
in picfun rad startAngle
offsetBy scaleVec 1.0 centerUnitVec
end;
fun triangleSlice lab percent color =
let fun makeslice radius startAngle=
let val endAngle = startAngle + percent/100.0 * 360.0
val unitVec1 = dcos startAngle, dsin startAngle
val unitVec2 = dcos endAngle, dsin endAngle
val pieSlice = triangle 0.0,0.0
scaleVec radius unitVec1
scaleVec radius unitVec2
val filledPie = pieSlice withFillColor color
val midAngle = startAngle + endAngle/2.0
val unitVec3 = dcos midAngle, dsin midAngle
val bisect = midpoint scaleVec radius unitVec1
scaleVec radius unitVec2
val labelLoc = bisect ++ scaleVec radius/4.0 unitVec3
val extLabel = text lab centeredAt labelLoc
in filledPie seq extLabel
end
in percent, makeslice
end;
Figure 1: Functions in the pie chart package
B's
should o ccupy; and a color with which to ll the
A's
slice.
Here is an example:
C's
F's
B's
A's
D's
pieChart 2.0
[triangleSlice "A's" 20.0 cyan,
triangleSlice "B's" 25.0 green,
triangleSlice "C's" 30.0 blue,
F's
triangleSlice "D's" 10.0 red,
C's
triangleSlice "F's" 15.0 yellow];
D's
explodeSlice works for any slice-drawing function:
pieChart 2.0
[slice "A's" 20.0 cyan,
B's
slice "B's" 25.0 green,
slice "C's" 30.0 blue,
slice "D's" 10.0 red,
slice "F's" 15.0 yellow];
A's
The de nition of a slice-drawing function leaves a
C's
F's
go o d deal of exibility. The function explodeSlice
takes a slice and moves it a certain distance away
from the center of the pie:
D's
pieChart 2.0
B's
[triangleSlice "A's" 20.0 cyan,
explodeSlice triangleSlice "B's" 25.0 green,
triangleSlice "C's" 30.0 blue,
explodeSlice triangleSlice "D's" 10.0 red,
A's
triangleSlice "F's" 15.0 yellow];
8 What a picture is slight return
F's
C's
The pro cess wherebywe arrived at the de nition
of Picture was not as smo oth as we describ ed it in
D's
section 3. Let us continue the analysis we b egan
there, and now consider the PIC not FPIC picture
pieChart 2.0
[slice "A's" 20.0 cyan,
explodeSlice slice "B's" 25.0 green,
box at last box.ne
slice "C's" 30.0 blue,
explodeSlice slice "D's" 10.0 red,
This places a new b ox at the northeast corner of the
slice "F's" 15.0 yellow];
most recently drawn b ox. The phrase \last box"
suggests that a picture may dep end up on the entire
set of previously-drawn pictures. Assuming these
We can also change the shap e of a slice. The func- are all collected into an environment, our de nition
tion triangleSlice draws triangular slices. of a picture would b ecome
Picture = Environment ! GraphicsContext ! dbox scale width lastbox + 0.5
BitMap Environment
width lastbox is a function from environments to
Our current de nition do es not allow the de nition
real numb ers, but then what is the typ e of \+"? It
of last box, precisely b ecause pictures do not see
cannot havetyp e realreal!real, so it is not the
an incoming environment. The result is that we
built-in multiplication of ML. Instead, it is a new
must assign a picture to an ML variable b efore we
multiplication op erator of typ e
can access one of its named p oints.
Environment ! real real! Environment !
This is the \obvious" de nition of Picture, and it
real.
was the rst one we used. Weworked with it for
quite a while b efore deciding it was untenable. We
still b elieve it is the correct de nition, in principle,
Clearly,we are on a slipp ery slop e: all the constants
but it makes a clean integration into Standard ML
and built-in op erators need to b e \lifted" to the typ e
imp ossible.
Environment ! whatever.
There are two problems with de ning pictures in
To see the other problem with this de nition of Pic-
this way. The rst is that it requires the rede nition
ture, consider this example:
of much of Standard ML. Consider a picture of the
form here we revert to FPIC-style syntax, though
let val b = dbox
lastbox is not an FPIC primitive
val c = dcircle at b pt "ne"
in b seq dtriangle seq c
end
dbox at lastbox pt "ne"
The obvious intention is that the circle should b e
dbox is a picture, so it has the typ e given ab ove.
drawn at the northeast corner of the b ox. However,
lastbox is a function from environments to pic-
this is not what will happ en. The waywehave de-
tures. Thus, pt must havetyp e
ned Picture, a picture is drawn only after all the
previous pictures have b een drawn. Thus, c is not
Environment ! Picture ! Name ! Point
drawn after b, but instead after the dtriangle. At
that time, it will lo ok in the environment, then cal-
so that the expression lastbox pt "ne" has typ e
culate where the northeast p oint ofabox would be if
Environment ! Point.Thus, at has typ e
drawn at that time, and then draw the circle there.
In short, there is no actual connection b etween b ox
b and circle c.
Picture Environment ! Point ! Picture
Instead, something more like this would b e needed:
So far, so go o d. But now consider
let val b = namePic dbox "b"
dbox at 1.0,2.0
val c = dcircle at lastpic "b" pt "ne"
in b seq dtriangle seq c
end
According to the typ e of at, whichwe just agreed
up on, the expression 1.0,2.0 must b e of typ e
Environment ! Point, not Point!We might de ne
At the time c is drawn, lastpic nds the most
a function recent picture named b and draws the circle there.
Even this is not a direct connection b etween b and
c;ifdtriangle were instead a picture containing a
fun constantPoint p = fn env => p;
picture named b, the circle would b e drawn there.
and then we could write the expression ab oveas
In any case, we nally abandoned this approachas
b eing to o confusing.
dbox at constantPoint 1.0,2.0
So, our language design approach do es not always
work as well as wewould hop e. Wewould liketo
This is annoying enough, but now consider maketwo observations, however, b efore ending this
discussion. One is that the two problems we've de- comes directly from PIC. We think this is a signif-
scrib ed are problems with integrating the new prim- icant di erence, b oth b ecause the facility is in fact
itives into the existing language. In particular, the used heavily in our examples as it was in PIC and
problems arise from the inescapable distinction b e- b ecause it represents the most interesting challenge
tween ML's ordinary variable environment and the in the language design.
picture environments created by FPIC primitives.
Neither problem would exist, as far as we can see,
if FPIC were designed as a new language. In fact,
10 Conclusions
the rst problem is already partially solved in the
functional language Haskell [3], in that literals and
built-in op erations can b e \lifted" in the way that
Wehave outlined an approach to sp ecial-purp ose
we require.
language design andn implementation using the
well-established technology of functional program-
Our second observation is that the technical prob-
ming languages. Our recommendation is to con-
lem describ ed in this section should not b e consid-
sider carefully the typ e of primitivevalues p eculiar
ered to imply that the language design is a failure.
to the domain, and emb ed this typ e in an exist-
We still consider that our original thesis has b een
ing functional language, such as Standard ML or
substantially b orne out.
Haskell. We illustrated this pro cess with resp ect
to FPIC, a language for picture-drawing inspired
by the language PIC, and illustrated some of its
b ene ts. FPIC is not p erfect, but wewould argue
9 Related Work
that the quality-to-cost-of-development ratio is very
high.
Wehaveacknowledged our debt to Kernighan's PIC
[4], and hop efully made clear how FPIC di ers.
There are quite a few languages for sp ecifying pic-
11 Acknowledgments
tures. We should particularly mention TimothyVan
Zandt's PSTricks [9], a collection of TeX macros, b e-
cause FPIC is implemented using them a BitMap
Wewould like to thank the anonymous referees for
is actually just a sequence of PSTricks macro calls.
their very helpful comments.
Another is Kristo er Rose's xyPic [8] package.
The closest relatives of this work are Chailloux
and Suarez's mlPicTeX [2] and Simon Peyton Jones
12 Availability
and Sigb jorn Finne's \simple structured graphics
mo del" [7]. Both are emb eddings of picture-drawing
FPIC can b e obtained from
primitives in a functional language ML and Haskell,
resp ectively. In Peyton Jones and Finne's work,
the typ e Picture contains abstract syntax trees of
http://www-sal.cs.uiuc.edu/~kamin/fpic
picture primitives; a program pro duces such a tree,
and then a renderer traverses this tree and pro duces
To run it, you will need to obtain Standard ML and
the picture.
the PSTricks macros; the FPIC web page has links
to sources for b oth.
Wehave emphasized in this pap er the search for
an appropriate de nition of Picture, and we con-
sider this an imp ortant step in the language design,
but this is a philosophical issue. Peyton Jones and
References
Finne may also have considered this issue and then
implemented the language as they did; they do not
[1] Adob e Systems Inc. PostScript Language Ref-
mention it. Chailloux and Suarez say nothing ab out
erence Manual. Addison Wesley, second edi-
what the typ e Picture is in their system.
tion, 1990.
The substantive di erence b etween FPIC and these
[2] Emmanuel Chailloux and Ascander Suarez. other two systems is that FPIC has a naming fa-
mlPicT X, a picture environment for LaT X. cility for p oints and pictures that they lack. This
E E
label "\\Huge Hello!" oval 2.0 1.0; [3] P. Hudak, S. Peyton Jones, and P.Wadler
eds., Rep ort on the Programming Language
Haskell Version 1.2,ACM SIGPLAN Notices,
This pro duces a typ e error, b ecause the second ar-
275, May 1992.
gumenttolabel must b e a picture, and oval is not
a picture rather, it is a function from two reals to
[4] B.W. Kernighan. PIC: A crude graphics lan-
a picture.
guage for typ esetting. Bell Lab oratory, 1981.
Top level de nitions of variables are signalled by the
[5] Donald E. Knuth. The T Xbook. Addison-
E
word val,asin
Wesley Co., Inc., Reading, MA, 1984
[6] Robin Milner, Mads Tofte, and Rob ert
val nose = dtriangle;
Harp ert, The De nition of Standard ML, The
MIT Press, Cambridge, MA, 1990.
Functions are usually intro duced by the keyword
[7] Simon Peyton Jones and Sigb jorn Finne. Pic- fun,asin
tures: A Simple Structured Graphics Mo del.
fun drawtree root subtrees = ...
[8] Kristo er H. Rose. XyPic User's Guide. 1995.
[9] TimothyVan Zandt. PSTricks: PostScript
The let expression is used to intro duce a temp orary
macros for Generic T X. 1993.
E
name.
let val v = e in e end
1 2
App endix A
binds the value of e to v and then evaluates e ,
1 2
returning its value.
We brie y review some asp ects of ML syntax,
enough to allow the examples to b e read by someone
Structures are of two kinds: tuples and lists. Tu-
not familiar with ML.
ples are written with parentheses, as in 1.0, 1.5.
Lists are written with square brackets, as in
Here is the rst example of FPIC in the pap er:
[dbox, dcircle, dbox].
We o ccasionally use the syntax fn var => expr to
box 1.0 2.0 hseq circle 1.5 vseq
label "\\Huge Hello!" oval 2.0 1.0;
de ne functions anonymously, usually when apply-
ing map.Thus, map fn var => expr L applies the
function that takes var to expr to each elementof
Function application in ML is indicated by juxta-
the list L.
p osition. Here, box isatwo-argument function
applied to arguments 1.0 and 2.0, circle is a
ML allows for user-de ned in x op erators, as in
one-argument function, label and oval are two-
argument functions. hseq and vseq are in x op era-
infix 6 cseq;
tors. As in many languages, backslash is an escap e
character so it must b e doubled within quotes.
The \6" gives the precedence of the op erator in the
Function application juxtap osition has a high
range 0 to 9.
precedence, so that the ab ove expression is equiv-
Lastly,two details ab out built-in op erators: The
alentto
tilde character ~ is the unary negation op erator.
Carat ^ is the string concatenation op erator.
box 1.0 2.0 hseq circle 1.5 vseq
label "\\Huge Hello!" oval 2.0 1.0;
Note that that sub expression oval 2.0 1.0 must
b e parenthesized, however, b ecause otherwise the
last part of the expression would b e parenthesized as
App endix B
The following are the FPIC primitives used in this pap er. This represents ab out one third of the total
numb er of FPIC primitives. Wehave also included those user-de ned op erations that are de ned in one
part of the pap er and used in a di erent part.
For each op eration, we give a generic call, with the arguments in italics. The form of the call shows whether
or not the op eration is in x. The names of the arguments indicate their typ es: pic for pictures, pt for p oints,
i for integers, r for reals, f for functions, and str for quoted strings.
pt1 ++ pt2 Addition of p oints
pt1 -- pt2 Subtraction of p oints
pt1 ** pt2 Multiplication of p oints
addNamedPics pic [str1, pic1, :::]
Add the list of named pictures to pic's environment
pic1, pt1 align pic2, pt2 Place pic1 and pic2,moving pic2 so that its p oint pt2 coincides
with pt1 on pic1
arrow pt1 pt2 Arrow from pt1 to pt2
pic at pt pic translated so that its reference southwest p ointisatpt
bezier pt1 pt2 pt3 pt4 Bezier curve from pt1 to pt4 with control p oints pt2 and pt3
box r1 r2 Box of width r1 and height r2
center pic The center of pic, calculated from its b ounding b ox
pic centeredAt pt pic translated so that its center is at pt
circle r Circle of radius r
pic1 cseq pic2 pic1 on top of pic2, their centers aligned
curvedharrow pt1 pt2 Arrow from pt1 to pt2, starting and ending with horizontal
segments
dbox Box of default size 1.618034 1.0
dcircle Circle of default radius 1.0
dcos r Cosine of r in degrees
doval Oval inscrib ed in dbox
dsin r Sine of r in degrees
dtriangle An equilateral triangle
frame pic pic with a b ox drawn around it user-de ned
group pic Same as pic, but considered as a single picture without subpic-
tures, for purp oses of calculating the subpictures of a containing
picture. For example, dbox hseq dbox hseq dbox has three sub-
pictures, but group dbox hseq dbox hseq dbox has two the
rst of which also has two.
height pic The heightofpic
pic1 hseq pic2 pic1 next to pic2
hseqlist [pic, :::] A list of pictures sequenced horizontally
hseqsplist gap [pic, :::] A list of pictures sequenced horizontally, with space b etween them
hseqtopsp gap pic1 pic2 pic1 and pic2 are drawn next to each other, their tops aligned, with
a gap b etween them user-de ned
hseqtopsplist gap [pic, :::] A list of pictures sequenced horizontally, their tops aligned, with
space b etween them user-de ned
hspace r Empty space of lenght r
label str pic Place str in the middle of pic
line pt1 pt2 Line from pt1 to pt2
midpoint pt1 pt2 The mid-p ointof pt1 and pt2
mkseqlist f Given sequencing function f , return the function that applies f to
a list of pictures
namePic pic str Give pic the name str
namePts pic [str1, pt1, :::] Add the named p oints to pic's environment
north pic North p ointofpic, calculated from its b ounding b ox
northeast pic similarly
northwest pic similarly
pic nthpic i The ith subpicture of pic
pic offsetBy pt pic translated by pt
oval r1 r2 Oval inscrib ed in box r1 r2
pic pic str The subpicture named str contained in pic
pics pic All the top-level subpictures of pic
place pic f pt Move pic so that the p oint f pic is at pt
placePt pic str pt Move pic so that the p oint named str is at pt
pic pt str The p oint named pt in pic
pic right r pic moved rightbyr
pic rotate r pic rotated counter-clo ckwise by r in degrees
pic scale r pic scaled by r in b oth dimensions
pic scaleTo pt pic scaled to t within pt
scaleVec spt pt multiplied comp onent-wise by s
pic scaleWithPoint pt1, pt2 pic scaled by pt1 see scaleXY, but without moving its p oint pt2
pic scaleXY pt pic scaled by x in the x direction and y in the y direction, where
pt =x; y
pic1 seq pic2 pic1 sup erimp osed on pic2
seqlist [pic, :::] The pictures pic, :::, sup erimp osed on one another
text str A picture consisting of the text str
triangle pt1 pt2 pt3 Triangle connecting pt1, pt2, and pt3
pic1 vseq pic2 pic1 on top of pic2
wedge r1 r2 r3 Create a wedge of a circle with radius r1 extending counter-
clo ckwise from angle r2 to angle r3
width pic The width of pic
pic withArrowStyle str pic drawn with a given arrowstyle, if it is a line; the arrowstyles
are as in PSTricks [9]
pic withFillColor r1, r2, r3 pic drawn in the color given byRGB values r1, r2, r3 all in the range 0-1