<<

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

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

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