Quick viewing(Text Mode)

The FL Project: the Design of a Functional Language 1 Introduction

The FL Project: the Design of a Functional Language 1 Introduction

The FL Pro ject The Design of a Functional

Alexander Aiken John H Williams

Computer Science IBM Almaden ResearchCenter

University of California Berkeley Harry Rd

Berkeley CA San Jose CA

email aikencs erkeleyedu email williamsalmadenibmcom

Edward L Wimmers

IBM Almaden Research Center

Harry Rd

San Jose CA

email wimmersalmadenibmcom

Abstract

FL is the result of an ort to design a practical functional based on Backus

FP This pap er provides an intro duction to and critique of the FL language The language eort is

analyzed from several p oints of view language design and user exp eriences Emphasis

is placed on the unusual asp ects of FL its strengths and weaknesses and how FL compares with other

Intro duction

In his pap er intro duced a simple notation for functional programming called

FP Bac The initial design of FP underwent considerable evolution in subsequentyears Wilb

Wila Bac HWWW HWWBWW WW BWW HWW culminating in the denition

of FL BWW Since the FL denition in a substantial implementation eort has b een underway

at the IBM Almaden Research Center to build an optimizing for and to test the viabilityof

programming in FL

This pap er is ab out the design of implementation of and exp erience with the FL language The

design of FL has b een heavily inuenced by FP and the philosophy set forth in Bac The core of this

philosophy is expressed in the op ening critique of con ventional languages Bac

Programming languages app ear to b e in trouble Each successive language incorp orates

with a little cleaning up all the features of its predecessors plus a few more Each new

language claims new and fashionable features but the plain fact is that few languages

programming suciently cheap er or more reliable to justify the cost of pro ducing and learning

to use them

Thus the ma jor goal of the FL design is to havea simpleyet exible and useful programming language

Simplicity means avoiding any language features b eyond the bare minimum needed to write realistic

programs The motivation for such spareness is more than the usual desire to avoid duplication in the

language In addition there is the b elief that a language ought to b e a useful everydaytool

for the and that a semantic description is useful to only if it is very simple

The design of FL has b een guided primarily by the desire for a simple and useful semantics A principle

that has b een adhered to throughout the pro ject is that at each step of the design pro cess the language

should have a full formal In fact the relative simplicityofvarious versions of the

language has b een judged primarily by the relative simplicity of the denotational semantics

With FP as a starting p oint following these principles has led to a language with many unconventional

asp ects For example FL has no static typ e system b ecause suchasystemwould add a layer of complexity

to the language denition and make it harder to learn This p oint contrasts with other functional

languages currently in use most of include static typ e systems as part of the language Another

unusual feature of FL is rstclass exceptions FL has exceptions b ecause it was considered necessary

to sp ecify formally what happ ens in the event of a runtime error such as division by zero Most

other functional languages do not provide runtime exceptions cho osing instead to leave the b ehavior

of runtime errors unsp ecied and implementationdep endent Standard ML HMT however has an

exception mechanism similar in spirit to FLs Like ML but unlike Haskell HWA FL is a strict

language

One desirable feature that is not a design goal of FL is eciency of compiled co de Not surprisingly

as a result some features of FL are dicult to compile w ell The goal of the implementation eort has

b een to see to what extent the simple clean semantics of FL can b e used as the basis for an optimizing

compiler that pro duces resp ectable co de

This pap er gives an overview of three related topics The rst topic is a description of FL Section

gives a brief informal description of FL together with numerous examples This section is intended to

acquaint the reader with the and style of FL programs without going into details Section

presents the formal syntax and semantics of FL Because FL is a language this section fairly

presents almost everything there is to know ab out FL For brevityhowever a few minor features are not

discussed the interested reader is referred to BWW

The second topic is a critique of FL on the sub jects of syntax typ es inputoutput exceptions and

order of evaluation FL is very dierentineach of these resp ects from most other functional languages

The purp ose of Section is to highlight these dierences explain why FL is dierent and to assess the

impact of these dierences

The third and nal topic is an overall assessmentofwhatitislike to program in FL ManyFL

applicationsincl udi ng some large applicationshave b een written and it is now p ossible to makesome

judgements ab out what works and what do esn work in the language and the implementation Section

relates the lessons learned from FL programming

A Brief Description of FL

This section provides an informal description of FL with examples In presenting the examples language

constructs are used without giving complete denitions in the hop e that seeing a few sample programs

will servetogive the avor of the language without requiring lots of text Each example consists of a

program an example of its use and some brief comments if necessary A formal denition of FL is given

in Section

Level Programming

FL is designed to b e a programming language in which it is easy to write clear and concise programs The

language design is based on the tenet that clarityisachieved when programs are written at the function

levelthat is by putting together existing programs to new ones rather than by manipulating

ob jects and then abstracting from those ob jects to pro duce programs This premise is emb o died in the

name of the language Function Level The emphasis on programming at the function level results in

programs that have a rich mathematical and that may b e transformed and optimized according

to an underlying algebra of programs

For example consider how a program SumAndProd which computes the sum and pro duct of two

numb ers is dened in a language based on the lamb da calculus One b egins with the ob jects x and y

constructs the ob ject hx y x yi note that sequences are written hx x i and abstracts with

n

resp ect to x and y giving a program

def SumAndProd x yhx y x yi

In con trast in FL one b egins with the functions and and applies the combining form construction

written Construction is dened so that for any functions f f the function f f applied

n n

to x pro duces the n element sequence whose ith elementisf applied to x

i

f f x hf x f xi

n n

Note that the application of f to x is written f x This results in the function level denition

def SumAndProd

A simple example of the use of SumAndProd is given b elow Throughout this section the relation

indicates one or more steps in the reduction of a combinatorial expression to its value

SumAndProd h i

h i

h h i h ii

h i

The next example illustrates how comp osition written can b e used to create new functions from more

primitive ones In general si is the primitive function that selects the ith element of a sequence and tl

is the primitive function that returns all but the rst element of a sequence In the following second is

dened to b e the same as the primitive s

def second s tl

second h i

s tl h i

hs tli h i

stl h i

s h i

Example shows a simple use of inx notation in expressions The functional which is dened so

that hf gi x f g x is applied to the two arguments s and tl In general fopg means

op hf gi

The following factorial program intro duces some new combining forms as well as recursion

def fact id id fact sub

fact

The function fact is built by applying the combining forms composition constant and conditional

to the functions id and the recursive function name fact As noted ab ove comp osition is dened

so that f g x fg x Constant is dened so that x y x provided y terminates and is not an

exceptionsee Section and conditional is dened so that p f g x f x if p x is true and g x

if p x is false Thus fact reduces to fact since is false fact reduces to fact

etc

One unusual asp ect of the FL style of programming is that explicit recursion is avoided Closedform

denitions using primitive recursive functions are preferred suchas

def fact intsto

intsto

intsto

i h

The function intsto for integers up to is a primitive such that intsto n h ni for a nonnegative

integer n Note that maps a sequence of numb ers into the pro duct of those numb ers for the empty

sequence multiplication is dened so that hi

There are twomainadvantagestosuch a First termination pro ofs b ecome very

simple The primitive recursivecombining forms preserve termination that is they are guaranteed to

terminate if their function arguments are themselves terminating Second programs are arguably easier

to understand since the inductive structure of the computation is in general simpler and more explicit

The former advantage is useful for an b ecause some interesting optimizations of FL

programs are valid only if functions are known to terminate for all arguments

Another example of closedform programming is the following program to compute the length of a

sequence

ha b ci

ha b ci

h a b ci

h i

This program works by simply replacing each element of the sequence b ya and then adding them up

The functional called map in many other languages is dened so that f hx x i hf x f

n

x i Note that asso ciates to the left ie x y z x y z so that a means a

n

A fancier example of closedform programming is the following O n log n sorting program

def sort tree hmerge hii id

sort h i

tree hmerge hii id h i

tree hmerge hiiid h i

tree hmerge hii hhi hi hi hii

merge hmerge hhi hii merge hhi hiii

merge hh i h ii

h i

The function tree takes a function and an ob ject and pro duces a function suchthattree hf zi hx x i

n

rewrites to z if n x if n and f htree hf zi hx x i tree hf zi hx x ii if n and

m m n

m dne The function merge merges two sorted sequences of numbers into a single sorted sequence eg

merge hh i h ii h i Notice that idmapsan nelement sequence into a sequence of

n singleton sequences This ensures that merge is applied to a pair of sequences in the base case

HigherOrder Functions

FL programs may b e higherorder In addition to the primitivecombining forms mentioned so far the

language includes mechanisms for dening new higherorder functions

There is a primitive function lift for raising functions to functionals The denition of lift is

lift f hg g i f g g

n n

lift is useful for writing closedform combinatorial denitions of higherorder functions In fact lift

is so useful that it has a sp ecial notation f lift f

Lifting can b e used to convert a rstorder function intoacombining form For example cat is a

function that concatenates sequences together Thus cat is a functional that combines sequencevalued

functions into a new sequencevalued function An FL string xyz stands for a sequence of characters

hx y zi Consider the following program that app ends the string Hello to the front of an argument

sequence

Hello cat id

Hello cat id World

cat h Hello idi World

cat Hello id World

cat hHello World id Worldi

cat hHello Worldi

Hello World

Another imp ortantway of dening higherorder functions in FL is by FL has a primitive

currying combinator dened so that

C f x y f hx yi

For example the function C maps a number x to a function that takes a number y and returns x y

An increment function can b e dened as follows

def inc C

inc

C

h i

Scop e

FL is a statically scop ed language An FL program consists of an expression together with a list of

denitions to b e used in evaluating that expression A denition list entry may itself b e a nested denition

list that exp orts only some of its denitions This provides a convenient hiding mechanism which together

with the facility for programmer dened typ es provides a technique for making encapsulated typ e

denitions see Section

The following program uses a subsidiary denition to compute the average of a sequence of numbers

def ave length where

fdef length g

ave h i

length h i

h h i length h ii

h i

Any expression in this case the righthand side of the denition of avecanhave an asso ciated environ

ment of function denitions In this expression the asso ciated environment is the singleton environment

dening length Such denitions are localtheir scop e of denition is limited to the expression to whic h

they are attached

Exceptions

Exceptions including runtime errors o ccur in practice in any programming language so some facility for

rep orting them is required For certain applications such as op erating systems that control the

of other pro cesses error handling is essential Errors and error handling are an integral part of FL FL

provides error handling in a purely functional manner

The domain of FL values is sub divided into the normal and the exception values Semantically

exception values are treated dierently than normal values All functions are strict with resp ect to

exceptions so that f x x for all functions f and exceptions x Sequences are also strict with resp ect

to exceptions a sequence collapses to the leftmost exception it contains so that hx yi x if x is an

exception This b ehavior is justied by the intended use of errors in FL errors represent a situation in

which something extraordinary has happ ened and therefore an error should p ersist until caughtoruntil

it escap es from and b ecomes the result of the program

Exceptions can b e raised by primitive functions For example the meaning of division by zero is an

exception

h i Exch arg h ii

Recall that a string xyz stands for the sequence of characters hx y zi In general if a primitive

function f is applied to an inappropriate argument x then f x evaluates to an exception of the form

Exchf arg xi

Most programming languages make a distinction b etween runtime errors such as division by zero

and compiletime errors suchastyp e mismatches Exclusiveofsyntax errors all errors are treated

uniformly in FL as exceptions For example adding a character and a numb er is not sensible In FL

the primitive function is dened so that it works as exp ected on sequences of numb ers and returns an

addition exception for all other arguments Thus using the program in example

ave h ai

length h ai

h h ai length h aii

hExch arg h aii length h aii

Exch arg h aii

arg h aii Exch

All FL primitives raise exceptions if applied to inappropriate arguments This makes FL a secure language

App An FL program never dumps core or otherwise terminates without returning a valid FL value

There is a sp ecial primitive signal such that signal x Excx for any normal value x This

provides the programmer with a way to raise exceptions directly In addition there is a higherorder

primitive function catch for catching and handling exceptions The function catch takes as arguments

two functions a body and a hand ler Informally catch hbody handleri x evaluates body x If body x is

not an exception the result is body x If body x is an exception Excy then the result is the handler

applied to a pair consisting of x and the contents y of the exception Note that this description of catch

is purely functional The functionalityofcatch is easily understo o d with an example A safe division

function that returns if division fails can b e written as follows

def safediv catch h i

safediv h i

catch h i h i

since h i

Thus safediv is exactly like in the normal case However

safediv h i

catch h i h i

hh i h arg h iii since h i Exch arg h ii

A formal denition of catch is given in Section

InputOutput

FL is an interactive language In order to accommo date interactive input and output and to facilitate the

writing of programs that require p ersistent storage all FL programs are required to map pairs into pairs

The rst comp onent of the pair can b e anyFLvalue but the second comp onentisalways a historyanFL

sequence that contains the currentvalue of the le system and the current status of all input and output

devices Thus the true functionalityofany FL program f is f hval historyi hval history i In

the examples the history comp onent has b een omitted

Most primitive functions are completely indep endent of the history comp onent and leave it unchanged

For example tl hh i historyi hh i historyi no matter what the contents of history may

b e A few of the primitives dep end on the contents of history but do not change the le system or

the status of any device eg get retrieves the most recent le system from the history Finally

some primitives b oth dep end on the contents of the history and alter it eg in maps hdev historyi to

hnext inp history i where next inp is the next value from device dev and the history is changed to

reect the fact that dev has b een read

It is imp ortant to note that without the history as part of its argument a primitive suchas in could

not b e a function since in reader could return dierentvalues dep ending on when it is called Including

the history p ermits a functional treatment of inputoutput and le system fetches Of course this implies

that al l functions must map pairs to pairs even programs suchastl that dont dep end on the history

However if the history comp onentwere to b e added explicitlyitwould then b e p ossible to treat it like

any other ob ject and thus to makemultiple copies of it and to dierent op erations to the various

copies Such manipulations would not b e consistent with the intended use of the history comp onentas

representing the current status of the IO devices and the le system

Therefore some metho dology is required whereby exactly one history is in existence at anygiven

time This is accomplished in FL by making the history comp onent implicit There is no p ossibilityofFL

programs treating the history in a way inconsistent with the metho dology since the history comp onent

may b e accessed or changed only by built in primitives suchasin and out and these primitives are

guaranteed to preserve the consistency of the history comp onent

Whenever p ossible in this pap er the history comp onent is not mentioned explicitlyFor example tl

is describ ed as though it simply mapp ed values to values This suppression of the history comp onent

except where necessary for understanding a program is the result of an attempt to reintro duce the notion

of an underlying into an otherwise basically functional language in a disciplined way Since

when implicit IO was develop ed the approach has b een generalized by the use of monadic IO see

Section

The following interactive program prompts for twonumb ers and prints their sum

def adder answer getnums

where f

screen sum cat intstring def answer out

def getnums prompt Enter a prompt Enter b

def prompt in keyboard out screen

screen out screen id def out

g

adder x

answer getnums x

answergetnums x

answer hprompt Enter a prompt Enter bii

answer h prompt Enter bi Enter a appears on the screen

and the user typ es

answer h i Enter b appears on the screen

and the user typ es

answer

out screen sum cat intstring

out screencat hsum intstring i

out screencat hsum i

out screen sum

out screen id sum

out hscreen sum i

hscreen sum i sum app ears on the screen

Patterns

The following program is similar to the safe divide in example The dierence is that if the

argument is not appropriate then an informative exception is returned

def newdiv ispair

isnum s isnum not iszero s

ss

diverr

diverr

def diverr signal newdiv arg id

ber This program rst checks that its argument is a pair then that the rst element of the pair is a num

and the second element of the pair is a nonzero numb er if so it divides the rst by the second otherwise

it returns an exception saying that newdiv ab orted when applied to its rst argument

newdiv h i

newdiv h i Exchnewdiv arg h ii since h i is not a pair

newdiv h i Exchnewdiv arg i since s h i

Such nested conditionals arise so frequently in practice that FL provides a primitive function pcons

p p hx x i is true if n m and p predicate construction with sp ecial syntax

n m i

x istrueforall i n and false otherwise Thus newdiv can b e written more succinctly

i

def newdiv isnum isnum not iszero ss diverr

Mo dern functional programming languages p ermit the naming of arguments to enable more mnemonic

expressions than ss The following program is equivalenttonewdiv but uses a pattern to create

function names for the arguments

def newdiv n m

isnum n isnum not iszero m

nm

diverr

diverr

newdiv h i

newdiv h i Exchnewdiv arg h ii since h i fails to match the pattern n m

newdiv h i Exchnewdiv arg i since not iszero m h i false

The pattern mechanism is dened so that newdiv is just a notational shorthand for newdiv That

is the pattern n m pro duces a predicate that tests for the structure of the pattern ispair in this

case and also denes the function names indicated by n and m in this case to b e selector functions

that corresp ond to their places in the structure in this case s and s resp ectively These function

denitions are lo cal their scop e is limited to the arms of the conditional

Notice that patterns are treated as an extension of predicate construction consistent with the FL

design philosophy of adding as few new constructs as p ossible The pattern n m is actually shorthand

for ntt mtt where tt is the everywhere true predicate see Section for a critique of this design

Using the full p ower of patterns results in the following equivalentversion of newdiv

def newdiv nisnum misnum not iszero nm diverr

newdiv h i

newdiv h i Exchnewdiv arg i the pattern fails since not iszero false

Again the pattern mechanism is dened so that newdiv is exactly equivalenttonewdiv To match

a pattern with emb edded predicates not only must the argumenthave the prop er structure but its

subcomp onents must pass the corresp onding predicates as well This abilitytoemb ed predicates in

patterns greatly increases the usefulness of the mechanism for writing terse easy to

read function denitions Note that the precedence of the inx op erators and is such that

misnum not iszero means misnum not iszero

The nal version of newdiv uses a sp ecial notation for dening a pattern on the argumentofa

userdened function

def newdiv nisnum misnum not iszero nm

newdiv h i

newdiv h i Exchnewdiv arg i

The shorthand notation used in newdiv is exactly equivalenttonewdiv In general in a denition

def f pat e if an argument x fails to match pat then an exception of the form Exchf arg xi

is generated This notation provides a convenientway for programmers to sp ecify where informative

exceptions should b e pro duced

Data Typ es

FL has userdened data typ es New data typ es are implemented as tagged ob jects of an underlying

representation typ e The language is designed so that all such tagged ob jects are initially in the domain

of FL values thus giving the programmer a convenient concrete way of thinking ab out and manipulating

data typ es Moreover these tagging op erations can b e hidden using the scoping mechanism thereby

pro viding a capability for abstract data typ e denitions

In keeping with the functionlevel data typ es are sp ecied by their charac

teristic functions The programmer supplies a predicate that is true for values that represent elements of

the typ e and is false for all other values For example consider an employee record with two elds one

for an employees name and one for an employees department An FL data typ e denition for sucha

record is

type emp isstring isstring

This typ e denition denes three functions a constructor mkemp that maps pairs of strings to elements

of emp a destructor unemp that maps elements of emp to pairs of strings and a predicate isemp that is

true for emp values and false for all other values An elementofdatatyp e emp with contents x is denoted

emp x

mkemp hWilliams i emp hWilliams Ki

isemp hWilliams Ki false

isemp mkemp hWilliams Ki true

unemp mkemp hWilliams Ki hWilliams Ki

mkemp h i Exchmkemp arg h ii since h i is not a pair of strings

To manipulate data typ es the FL programmer writes functions that work on the representation For

example selectors for the name and department elds can b e dened as follows

def name isemp s unemp

def dept isemp s unemp

name emp hWilliams Ki Williams

dept emp hWilliams Ki K

dept h i Exchdept arg h ii since isemp h i false

Note that in the denitions of name and dept the predicate isemp is used as a guard on the lefthand

side This notation has the same meaning as when a pattern is used on the lefthand side Section

except that no function denitions are made

An alternative denition of the data typ e emp uses a pattern in the typ e predicate When a pattern

is used to dene a data typ e the functions dened by the pattern b ecome selector functions for the data

typ e

type emp nameisstring deptisstring

This type denition denes mkemp unemp isemp name and dept exactly as ab ove

AFormal Denition of FL

This section provides a formal denition of the syntax and semantics of FL Section gives a grammar

for the subset of the language used in this pap er and provides a brief discussion of the syntax Section

describ es the FL semantic domain Finally Section gives a meaning function that assigns elements of

the semantic domain to FL programs Readers less interested in the formal denition of FL may wish to

skip ahead to Section which contains a commentary and comparison with other languages returning

to this section only as needed to clarify the subsequent discussion

Syntax

An FL grammar is given in Figure The grammar is written using a mostlyconventional BNF syntax

the conventional notations used in Figure are

nonterminal nonterminals are in italic font

terminal terminals are underlined in b old font

denition

alternatives

In addition there are nonstandard notations convenient for sp ecifying sequences FLs prime notation

optional syntax and grouping



x zero or more elements of typ e x separated by p

p

x one or more elements of typ e x separated by p

p

p p p p

with zero or more primes

de optional item

fg grouping

smal l italics is a comment describing

construct

smal l italics

Uses of fg are p otentially ambiguous b ecause curly braces are used b oth in FL environments and as

g which metasymb ols of the grammar To emphasize the distinction uses as FL syntax are written f

is consistent with the notation for terminal symb ols

The grammar in Figure is only a subset of the the full FL language The omissions are three

additional pro ductions for more general forms of patterns one environment op erator one additional

form of function denition a form of lamb da abstraction and approximately a dozen pro ductions for

dening assertions a of formal commentBWW The more general forms of patterns are used

in practice but infrequently The other omitted features are rarely used

To complete the denition of FL syntax it is necessary to describ e its lexical structure as well as

precedence rules for inx notation FL is unremarkable in b oth resp ects so a brief informal description

should suce The lexical units of FL not dened in Figure are numb ers identiers and op erators

Identiers are strings over letters numb ers and some sp ecial characters Identiers b egin

with an identier letter whichisany of the usual Roman letters plus the sp ecial characters Numbers

b egin with a numb er or a prex or FL has a xed set of op erator names suchas and

Except for unary and in numb ers op erators always stand for themselves and cannot b e included

in numb ers or identiers

There are levels of precedence for inx and unary op erators in FL Precedence is xed and cannot

be changed by the programmer A consequence of this is that all programmerdened function names

have the same precedence when used in inx expressions

Although simple the lexical structure and precedence rules of FL have some annoying problems

These problems are discussed as part of a general critique of FL syntax in Section

The Domain

The FL semantic domain is dened in a standard way as the solution of a system of recursive equations

The pro of that these equations have a solution is straightforward using standard techniques Sto

Before presenting the domain equations a few denitions are required The FL domain denoted D

FL

contains atoms functions sequences written hx x i tagged pairs written i x where i is an

n

integer tag and exceptions written Excx There is a partial order on the elements of D suc h

FL

that the following all hold

x for all x

hx x i y i x y for all i n

n n i i

Excx Excy x y

i x i y x y

f g f x g x for any functions f and g and for all x

Let X D Anupper bound of X is an element y such that x y for all x X Theleast upper

FL

ound of X written tX is the least value y such that x y for all x X The set X is directed if every b

nite subset of X has an upp er b ound in X A function f is continuous if f tX t f x for

xX

every directed set X

FL functions map a value history pair to another value history pair A history is a p otentially

innite sequence of elements of D The set of nite histories consisting of nite sequences of elements

FL

p p

expr expr expr

j expr j j cond j expr atom j name j seq j

application primed expression

p



p 

p

expr

expr

expr expr expr

j j j j expr where expr

expr

constant construction predicate constr inx expr

true j false

atom character j number j

truth values



seq hexpr ij string



string character

p

cond expr expr d exprejpat expr d expre

 

patlist fpat expr g pat f pat expr g

expre namedpat

patlist

pat j

elementary pattern pat construction

expr pat j expr pat

env fdefn g j exp ortname name string j PF j env j hide env j lib

env uses env j env where env j env union env jfenvg

defn def name dpat expr eexpr j nrdef name dpat expreexpr j typ e identier pat

name identier j operator

Figure An FL grammar

of X is written X The set of innite histories consisting of innite sequences of elements of X is

written X The ordering on D is extended to valuehistory pairs as follows x h x h if

FL

x and h is a prex of h or x x jhj jh jand h h for corresp onding elements h h of the

i i

i i

two histories

The FL domain includes sequences tagged pairs to represent data typ es and exceptions Notations

for these three kinds of values are given by the following denitions

Seqs X fhx x ijx X n g

n i

Tag X f i x ji I x X g

ExcX fExcxjx X g

Denition The domain D is dened to b e the solution of the following system of equations

FL

D D E

FL FL

FL

D Atoms Seqs D TagD DH DH

SH

FL FL FL

DH D D fgD

FL

FL FL

fg E ExcD

FL

FL

Atoms Integers Floats Characters ftrue falseg

The function space X Y is the set of continuous strict and honest functions from X to Y A function

SH

f is strict if f e h e h for all e E A function f is honest if whenever f x h x h then

FL

h is a prex of h

The restriction of D to strict and honest functions is motivated by the following considerations

FL

FL incorp orates IO through an explicit history comp onent that is manipulated by certain primitive

functions This requires that the orderofevaluation of FL expressions b e sp eciedotherwise the order

of changes to the history would not b e welldened If program semantics must dep end on the order of

evaluation then a strict semantics is preferable to a lazy one b ecause it is much easier for a programmer

to understand and predict the order of events There are other reasons that FL is strict b esides IO

these are discussed in Section

The restriction to honest functions stems from the desire to admit only functions that treat the history

comp onent in a manner consistent with the view that the history is a record of all external events Thus

a history can b e extended but an event once it o ccurs cannot b e mo died or removed from the history

The honest functions only extend histories

Finally DH denes the set of valid valuehistory pairs The structure of DH is determined by the

role of the history comp onent only an innite computation ie one whose meaning is can pro duce

an innite history and any nite computation can pro duce only a nite history

Semantics

Let the set of all functions names b e N Anassignment is a mapping ND fg The value is

FL

used to denote a function name that has no binding The meaning of an FL expression is given bytwo

functions

Expressions Assignments D DH

FL

Expressions Assignments N Assignments fg

Informally computes the meaning denoted by an expression while computes the assignment denoted

by an expression is used to give meaning to environments of FL functions The functions and are

meaningful only in the case that the assignmentgives a non meaning to every free function name in

the expression

The Function

The meaning function for expressions is given in Figure New notation used in Figure is describ ed

below A p oint of p otential confusion is that the same notation is used b oth for FL expressions and

semantics in applications f x and sequences hx x i Since expressions are written with a b old font

n

ie x x andvalues with an italic font ie x x the meaning is always clear from context There

is no FL syntax for tagged pairs and exceptionsresp ectively i x and Excx so these notations

always denote values

e is shorthand for e where PF This notation is used in cases where In Figure the notation

FL syntax can b e desugared into applications of primitive functions Tomake clear where primitive

functions are meant one can write e where PF which has the eect of binding free function names in

e to their primitive denitions the environment PF stands for primitive functions This degree of care

in the resolution of primitive function names is required b ecause in contrast with many other languages

FL p ermits primitive function names to b e redened

The following prop osition gives the denition of FL function application

Prop osition There is a function D DHD satisfying

FL FL



x h if x E



FL









y E y h if x D

FL

FL

x y h



Exchapply arg hx yiih if x D y D x is not a function



FL FL 







xy h otherwise

The meaning of is the same as the meaning of the primitiv e function apply

One auxiliary function is used in the denition of The function F turns an arbitrary expression x

into a function that applies the meaning of x to an argument

F x y hx y h where xVh x h

Note that F has the eect of delaying the evaluation of x until a second argument is supplied The

op eration combines environments of function denitions and is dened in Section

aVh a h if a is an atom

f Vh V f h if f is a function name



hy y ih if fy y g E

n n n FL

hx x iVh

n

y h if fy y gE and y E and j n

j j j  FL j FL



h h

where

x Vh for i n y h

i i i

i

c c Vh hc c ih

n n

xVh xVh

p

p

x x Vh apply hx x iVh

p

p

xVh K xVh

p p

x x Vh cons hx x iVh

n n

p

p

x x Vh pcons hx x iVh

n n

x Vh lift xVh



cond hy y y ih if fy y y g E

FL

p x x Vh

y h if fy y g E and y E and j

j j j  FL j FL



y h pVh





where

y h x pV V h







y h x pV V h

p p

p xVh p x signal cond arm idVh

p

p

cond hp x x iVh p x x Vh



y x Vh if y E

FL

x x Vh

y h if y E

FL

where y h x Vh

f xVh xVh

f V h tt h

x x x Vh x hx x iVh

x where E Vh xEV V h

eVh if none of the ab ove apply

Figure The function

The rest of this section provides commentary on the rather terse formal denition of in Figure The

purp ose of this commentary is b oth to explain the formal denition and to highlightsomeunusual asp ects

of FLs semantics Judgements ab out the merits of the various features are p ostp oned to Section

The function gives FL a leftmostinnermost order of evaluation For example if a sequence contains

an elementofE the sequence collapses to the leftmost elementofE in the sequence The semantic

FL FL

op erator is dened to b e compatible with leftmostinnermost evaluation thus Excx Excy Excx

FL provides sp ecial notation for the combining forms construction predicate construction

conditional lifting constant and application These notations corresp ond to the primitive

functions cons pcons cond lift K and apply resp ectively The sp ecial forms for cons pcons cond

and K are inherited from FP The new notations for lift and apply are intro duced b ecause these functions

are used p ervasively in higherorder FL programming

The intro duction of the sp ecial syntax for certain function names creates a problem with the prime

notation for lifting Any function name can b e lifted using a prime for example cons hf gi applies

lifted cons to f and g However the prime notation do esnt extend automatically to the sp ecial forms

Thus FL has additional syntax for lifting each of the sp ecial forms becomes becomes

etc The semantic function translates this notation into applications of the appropriate primitive

functions

In a conditional p f g the predicate p may b e a pattern The semantics is such that any denitions

made by p are lo cal to the expressions f and g see Figure and Figure Note that p maynotbea

pattern in the expression cond hp f gi Extending FL to include this case would require giving meaning

to sequences containing patterns This would intro duce a new semantic category into the language since

a sequence containing a pattern is neither a simple sequence nor a pattern

The syntax of FL also forbids anycombination of lifting and patterns see Figure Since the

p p

z should b e cond hx y zi for consistencyallowing priming and patterns would translation of x y

also require admitting patterns in sequences Beyond this problem it is not even clear what a pattern in a

lifted conditional should mean For example do the dened selectors apply to the rst curried argument

or the second

The denitions sp ecied by patterns are describ ed by the function see Section The predicate

sp ecied by a pattern is describ ed by For an elementary pattern fx the predicate is just the function

x The predicate after the dot may b e omitted ie f in which case the predicate is the constant true

function tt In a pattern construction p p the predicate is pcons hp p i The primitive

n n

pcons is dened so that the pcons hp p i hx x i is true if p x is true for all i

n n i i

Finally note that FL has a general inx notation Any function name can b e used inx without

sp ecial syntax

The Function

The meaning of FL environments is given by the function in Figure The function also serves to give

meaning to the function denitions made by patterns Assignments are denoted V W The following

auxiliary functions on assignments are used in the semantics

domV ff j V f g



V f if V f

V V f

V f otherwise



V V if domV domV

V j V

undened otherwise



if f X

V X f

V f otherwise



x if f g

f xg

otherwise

The assignment V V is the union of V and V with clashes resolved in favor of V The assignment

V jV is a symmetric union of two assignments with disjoint domains The assignment V X is V with

domain restricted to X Finally f x is an assignment dened at the single p oint f

The rest of this section elab orates on the denition of in Figure The rst several clauses explain

the meaning of the various environment op erators The dierence b etween e where e and e uses e

is that the former exp orts only the denitions of e whereas the latter exp orts denitions from b oth e

and e with clashes resolved in favor of exp orting the denition in e PF is the environment of primitive

functions PF is discussed further in Section The environment liblibname is the FL mechanism

for imp orting functions from a precompiled of function denitions

The semantics of function denitions is straightforward except for the use of patterns and the function

F on the righthand side of denitions Patterns are translated into a conditional where an appropriate

exception is generated in the case where the predicate fails The function F is applied to guarantee that

the righthand side of a function denition is in fact a function For example the denition def foo

is a valid FL function denition The meaning of this function is F y h y h Thus foo is a

function that returns Exchapply arg h xii when applied to x The function F is the identityon

functions so if the righthand side of a function denition is already a function then F do es not change

it

erting nonfunctions into functions may seem unnecessarily elab orate An This mechanism for conv

obvious alternative is to try to forbid function denitions where the righthand side is not a function

and thus avoid the use of F This approach do es not work for two reasons First b ecause FL is a

strict language a lazy op eration like F is needed somewhere to give recursive equations nontrivial least

solutions Second there is a dicultywithIOTo test whether the righthand side of a denition is

a function or not in general it is necessary to evaluate it This cannot b e done at compiletime if the

e where e V e e V V

e uses e V e e V V e V

e union e V e V j e V

f f eV eV ff f g exp ort

n n

hidef f eV eV Nff f g

n n

PF PF



V defn V j j defn V V



n n





fdefn defn gV least V st

V if defn nrdef

n

i



V



i



V otherwise

def f eV f F eV

nrdef f eV f F eV

signal f arg idV def f p eV f F p e

nrdef f p eV f F p e signal f arg idV



W isx cond hhastag i tt i

x











i W mkx cond h F eV tag i y hExchmkx arg y ih



x



typ e x eVW st

W unx cond hW isx untag i y hExchunx arg y ihi

x











eVf W unx if f domeV







W f



otherwise

f xV f id

f f V f V j j f V V

n n n



f Vf si if f domf V

i i

where f V f

i

i

otherwise

Figure The function

evaluation involves IO For example consider the denition def foo s h adder i where adder is

the function dened in example The use of F in the semantics makes clear that the IO happ ens

each time that foo is applied

Typ e declarations simply add new functions to the environment The typ e declaration type x e

denes the functions mkx unx and isx as well as any selectors dened by e if e is a pattern The tag

i is selected by the implementation and is guaranteed to b e unique even if there is another declaration

x

type x e in another scop e The function is used to prevent IO from taking place in the typ e

predicate see the denition of in Section The motivation for this design is that typ es are intended

to b e xed sets of values that is the set of values that are elements of a typ e should not dep end on

external state For this reason the function is used to ensure that the denition of a typ e cannot

dep end on the history comp onent of the semantics

Finally the functions dened by a pattern are given by the last three clauses An elementary pattern

f or f x denes f to b e the identityIff is emb edded in a pattern construction then the denition

of f is comp osed with the appropriate selector function for f s p osition in the pattern Note that if a

pattern is given for a typ e denition that any selectors dened by the pattern are comp osed with the

destructor for that typ e

PrimitiveFunctions

The primitive functions of FL are exp orted by the environment PF There are a lot of primitivesab out

in all Denitions of the more imp ortant primitives used in this pap er are given in Figure In this

that f g and f are functions and that i is gure it is assumed that x y x and y are elements of D

i i i

FL

an integer These denitions omit some cases The missing cases are dened uniformly for all primitive

functions as follows In an application f x if f or x is an exception or then the meaning of the

application is an exception or by strictness Otherwise if f x do es not match the pattern in Figure

hf arg xi For a secondorder function f x y the rules for primitive f then the meaning is Exc

are the same except that exceptions generated by the primitivehave the form Exchf arg hx yii

The functions cond catch and gamma merit further discussion It is wellknown that a strict con

ditional op erator is problematic since strictness requires that if p then q else evaluate all of p q

and r The desired b ehavior is of course that q should b e evaluated only if p is true and r should b e

evaluated only if p is false

The FL function cond is strict as are all FL functions but the desired semantics is still achieved

b ecause cond is a higherorder function That is cond hp q ri evaluates all of p q and r but in this

case p q and r are functions that are used to dene the conditional When an additional argumentis

supplied cond hp q ri x evaluates to q x if p x is true and r x if p x is false Note that truth is denoted

byany nonfalse nonerror value in FL a convention adopted from Lisp Thus a strict functional

version of conditional can b e had by making conditional a secondorder function The fact that cond is

a second order function in FL has a large impact on programming style The function cond is the only

way to write a conditional in FL Because conditionals are used heavily in programming this essentially

forces FL programmers to write at the function level

The function catch provides the only mechanism for catching and handling exceptions in FL All FL

functions are strict with resp ect to exceptions so that catch ExcxExcx Thus it is not p ossible

to dene catch so that it simply can b e comp osed with another function ie catch f cannot handle

exceptions generated by f b ecause catch is strict The trick to dening a that can handle

exceptions is to make it higherorder Thus catch is a function that takes two functions f and g and

pro duces a function that returns g hx yi if f x Excy recall Example in Section

Both cond and catch are instances of a general technique for achieving desired functionalityina

strict language the lesson is that functionality often can b e hidden in the internals of a higherorder

function denition A nal example is which suppresses IO Intuitively converts any function f into

a function that cannot p erform IO If f do es no IO then f x f x If f do es attempt to p erform IO

then the result is a gamma arg exception and the history is unmo died Note that the denition of

in Figure is purely functional The function is used primarily in the language semantics to guarantee

that no IO takes place as part of a userdened typ e constructor It is also used by programmers to

make explicit p ortions of programs that do not p erform IO

Commentary and Comparison With Other Languages

This section provides a wideranging comparison of FL with other languages as well as opinions on what

is go o d and bad ab out FL The discussion is organized around four topics syntax typ es IO and

exceptions included in the discussion of exceptions are remarks on the order of evaluation in FL These

topics are the main p oints of contrast b etween FL and other functional languages Several sp ecic items

are discussed under each general topic The choice of items is ad hoc but every item illustrates either

something esp ecially unusual ab out FL a particularly strong or weak p oint of the language design or an

interesting relationship to other languages

Syntax

FL programs are written at the function levelprograms are formed from other programs using higher

order combinators For example recall the program SumAndPro d from Section in which one b egins

with an ob ject hx y x yi and abstracts over the variables of the ob ject to obtain the program x yhx

y x yi

e the answer by insp ect One advantage of the lamb dabased approach is that the function lo oks lik

ing the form of the b o dy of the lamb da expression one can get an idea of the answer ie the expression

x yhx y x yi clearly returns a pair the rst comp onent of which is a sum and the second comp onent

of which is a pro duct On the other hand there are two apparent disadvantages to the ob jectlevel style

in this case the size of the resulting program and the need to name and the b ound variables

K x y h x h

appl y hf xih f x h

comp hf f i x h f f x h

n n

cons hf f i x h hy y ih where y h f x h

n n n i i i i



y h if y E



FL









f x h if y false

cond hf f f i x h



f x h otherwise











where y h f x h



false h if x hx x i

n











y h if f y y g E ffalse g and y E



i i i FL i FL



pcons hf f i x h

false h if i ny false

n

i i









true h otherwise



n







where y h f x h

i i i i i

id x h x h

tt K true

K false



y h if f x h y h

f x h

Exchgamma arg x ih if f x h y h h h

f hx x ih hy y ih where y h f x h

n n n i i i i



y h if f x h y h y D fg

FL

catch hf gi x h

x h Excy h g hx y ih if f

sig nal x h Excx h

intsto i h hiih if i



true h if x i y

hastag i x h

false h otherwise

tag i x h i x h

untag i i x h x h

si hx x ih x h if n i

n i

Figure Some elements of PF

The FL version of this program accomplishes the same thing at the function level byproviding

syntax for the function cons that parallels the syntax for sequences hi resulting in a shorter expression

without junk For a more complete discussion of the advantages of programming with a

carefully selected collection of combining forms with rich algebraic prop erties see Bac Wilb

These advantages notwithstanding FL syntax is p eculiar particularly to programmers who are fa

miliar with other functional languages Some of the p eculiarity is sup ercial p eople who use FL for the

rst time often are surprised at how easy it is to write FL programs Still FLs syntax app ears to have

more problems than merits A few of each are discussed in this section

Prime Notation

While FLs combining forms facilitate the writing of rstorder functions writing higherorder functions

is less convenient FLs prime notation is an attempt to make higherorder combinator expressions lo ok

like the values they compute

Consider a function f g The lamb da calculus version of this function is xhfx gxi function

application of f to x in lamb da calculus is written as the juxtap osition fxTo abstract over f in the

lamb da expression one writes fxhfx gxi To do this in FL it is necessary to write a com binator

that when applied to f evaluates to f g One way to do this is to write

cons id g

To see that this works apply it to f

cons id g f

cons hid f g fi

cons hf gi

f g

This program isnt awful but it isnt easy to read A b etter version uses lifted construction

id g

Now it is clear what the result of the function will b e a lifted construction returns a construction the

argument is substituted for id and g is replace by g This denition is equivalent to the previous one

since

id gi cons id g id glift cons h

The next step is to abstract the program again with resp ect to g ie gfxhfx gxi One

solution is

cons cons id id

This program is awfulit is not at all clear at a glance what this program do es With prime notation

one can write

id K

The double prime says that the result is a construction after two arguments are supplied id throws

away the rst argument and keeps the second K throws away the second argument and keeps the rst

It is straightforward to show that this program is equivalent to the unreadable one ab ove

To new FL programmers this kind of programming is usually mysterious but exp erienced users

b ecome surprisingly adept at reading and writing functions using prime notation In short the prime

notation provides a concise and fairly readable notation for writing higherorder combinators It is not

as readable as the lamb da calculus but it is vastly sup erior to an unsugared combinator language An

op en question are FLs conveniences at the function level worth the inconveniences of priming at higher

levels

Inx Notation and Precedence

Most contemp orary functional languages supp ort inx notation The favored strategy adopted in ML

and Haskell is to provide a sp ecial form for declaring certain names to b e inxable along with a

precedence level which is usually an integer in the range Some primitive functions are automatically

inx op erators with presp ecied precedences

In contrast FL has a general inx notation and no precedence declarations Any FL expression

x x x means x hx xi This is quite convenient since a programmer may use an op erator inx

prex or anycombination of the two even in the same expression Other advantages are that the rules

are simple and easy to rememb er and no new kind of declaration is intro duced into the language

A problem with general inx comes up in printing expressions b ecause the must makean

arbitrary decision whether to displa y a function of two arguments prex or inx A reasonable solution

is to print all primitive op erations that are normally inx eg etc inx and all userdened

functions prex

Unfortunately general inx notation do es not come for free General inx uses up a languages most

valuable lexical unit the blank In most functional languages a blank denotes function application eg

fxyis f applied to x and y In FL fxyis inx application of x Thus the cost of general inx is that

another notation is required for application this is why is used to denote function application in FL

General inx notation works reasonably well for rstorder expressions where the most common inx

application is function comp osition In higher order FL expressions however plain function application

is used at least as often and usually much more often than inx The exp erience with FL programming

is that it is often dicult to write FL programs that are not cluttered with symb ols In retrosp ect

although general inx is a nice idea it do esnt payitsweight in practice

A general problem with inx notation that FL shares with other functional languages is precedence

FL has levels of precedence for the unary and inx p ortions of the grammar This has proven far

to o much to exp ect FL programmers to rememb er let alone use The following example showsatypical

FL programming error involving precedence Assume one wants to write f g where g x y z is a

conditional Then f x y z do es not parse as desired since binds more lo osely than A correct

version is f x y z The same problem exists for z and comp ositions trailing the conditional Since

FL has no static typ e checking the rst hint of a problem is normally a runtime exception in the absence

of program analysissee Section Usually the exception helps the programmer to nd the error

almost immediately but o ccasionally substantial time is lost searching for precedence mistakes

Although FL has more levels of precedence than other functional languages FL is probably no worse

in practice This is b ecause FL programmers have dicultyrememb ering and applying more than a

small handful of the precedence rules anyway so levels would not b e b etter than The solution

most programmers adopt is to keep function denitions small by making many subsidiary denitions

This style helps to make programs readable if informative function names are chosen and reduces the

opp ortunities for a precedence mistake

Sp ecial Notation

FL has a lot of sp ecial notation adopted from FP FP is a rstorder language with userdenable rst

order functions and a xed set of secondorder functionals the combining forms Because of the sp ecial

role of the combining forms it is reasonable that FP has a sp ecial notation for each This design do esnt

work so well in FL FL is a higherorder language in which programmers can dene new secondorder

and higher order functionals With rstclass higherorder functions giving sp ecial notation to a few

functions seems arbitrary It also complicates unnecessarily

Another problem with FLs sp ecial notation is that some of it is to o economicalie a one character

change can result in a valid but completely dierent program from the one intended The hardest FL

programming error to nd is an example of this phenomenon Recall that an elementary pattern has the

form fp where f is a function name and p is a predicate This pattern denes a predicate that matches

values for which p is true If p is just tt that is the pattern should matchanyv alue then FL provides

a convenient shorthand f that means the same thing For example f g is a pattern matching all

pairs f is a selector s for the rst comp onentandg is a selector s for the second comp onent As

discussed in Section allowing emb edded predicates in patterns is a p owerful feature and is very useful

in eliminating nested conditionals

However consider what happ ens if a is omitted The pattern f g is still syntactically well

formed But now f is just a free function name and resolves to whatever denition is visible in the current

scop e If one is lucky f is not dened and a results Unfortunately b ecause programmers

tend to reuse the same names for selectors in patterns the chances are quite go o d that f is dened in an

outer scop e p erhaps it is the selector s It is very easy to overlo ok the fact that a has b een omitted

even when the programmer knows there is a mistake in a pattern A b etter language design would b e to

eliminate the shorthand f and force programmers to write ftt thereby making the dierence b etween

the right and wrong versions muchmoreobvious

Typ es

FL is dynamically typ edin principle all typ e checking is done at runtime In this resp ect FL is more

closely related to Lisp and Scheme than it is to ML or Haskell

Many p eople consider static p olymorphic typ e checking to b e one of the central features of functional

languages The advantages of static typ e checking are great programming is b oth more secure since

bugs that arise from typ e errors cannot b e intro duced into a program and programs run faster since

no dynamic typ e checking is required On the other hand there are costs First b ecause no static

typ e system can b e b oth sound and complete ie no typ e system can recognize exactly the set of

programs that make runtime errors some programs must b e rejected that are otherwise meaningful

Second the language description b ecomes more complex and programmers must understand p olymorphic

typ e checking to write working programs The former p oint is the source of an endless debate b etween

adherents of dynamic and static typing ab out whether any of the programs rejected by static typ e systems

are really useful The latter p oint is indisputable but exp erienced programmers have little if any trouble

dealing with static typing Within the functional programming communityanoverwhelming ma jority

supp orts static typing

FL has taken a dierent direction exploring to what extent an implementation of a simple dynamically

typ ed language can achieve the security and eciency of a statically typ ed language In FL typ e errors

result in runtime exceptions For example the application s would b e a static typ e error in most

languages since s is meant to b e applied to lists but results in an s exception in FL This design

imp oses a substantial burden on the implementation b ecause applications of primitives of s must always

test to ensure that arguments are of the prop er typ e One of the goals of the FL implementation has

b een to investigate to what degree the eects of static typ e checking can b e recovered through program

optimization replacing primitives suchass byversions that p erform no typ echecking in contexts

where program semantics are not changed For example in the program s the function s is

guaranteed to b e applied to a nonempty sequence Therefore in this program s can b e replaced by

a dierent function Safe s that p erforms no runtime typ e check To determine where runtime typ e

checking can b e omitted the FL implementation uses a typ e inference

FL Typ e Inference

Although the FL language is dynamically typ ed the FL implementation has a p owerful typ e inference

system The typ e system is not part of the language denition In this resp ect it functions as a traditional

program analysis whichmay b e used at the discretion of the programmer or compiler but is not required

This section very briey describ es the FL typ e system and presents two short examples The interested

reader is referred to AWAWL for details

Functional languages such as ML and Haskell havetyp e systems based on the wellknown Hind

leyMilner typ e system DM HindleyMilne r typ es include typ e constructors suchasInt Bool and

In fact s can b e optimized to as describ ed in the following section

Listt where t isatyp e function typ es t t typ e variables and quantied typ es t

Typ es denote sets of values Typ e constructors denote sets of primitive and userdened values suchas

integers b o oleans and lists A function typ e t t denotes the set of functions mapping elements

of t to elements of t Avariable stands for an unknown typ e and quantied typ es denote sets of

p olymorphic values For example the function s that selects the rst element of a sequence has the

HindleyMilner typ e

sList

where List stands for all FL sequences with elements drawn from the typ e and the notation is

read has typ e

The FL typ e system is an extension of the HindleyMilner system In addition to the HindleyMilner

and complement t typ es as well as recursive typ es FL has restricted intersection t t union t t

typ es E There is also a least typ e and a universal typ e The FL typ e system abbreviated

FLT has several nice prop erties

If a program has a HindleyMilner typ e then the HindleyMilner typ e is derivable in FLT

Every program is typable in FLT

Every program has a minimal FLTtyp e

The minimal FLTtyp e is computable

FLTs minimal typ es are the analog of principal typ es in the HindleyMilner system The minimal typ e

of a program e is the smallest typ e derivable for e within the typ e system The notion of a minimal typ e is

somewhat dierent from the notion of a principal typ e Principal typ es are dened syntactically whereas

minimal typ es are dened semantically Principal and minimal typ es coincide in the HindleyMilner

system FLT has minimal typ es but not principal typ es AWL

For brevity a formal development of the FL typ e system is not presented here Two examples should

suce to illustrate howtheFLtyp e system diers from the HindleyMilner system The rst example is

the program s This program is a constant function that returns The general HindleyMilner

typ e for a primitivesuchass is

s List

The typ e List is dened by the recursive equation

List Cons List Nil

Using this typ e for s the b est typ e that can b e assigned to the sub expression s in s by the

HindleyMilner system is

s ListInt Int

This typing proves that s always is applied to a list so s do es not need to check its argument at run

time to ensure that it is a list In addition since typ e inference succeeds on this program the programmer

can b e condent that s is not applied to say a oating p ointnumber

For this program the FL typ e system can improve on the eciency and security of the HindleyMilner

algorithm Because Nil is a p ossible value of the List typ e under the HindleyMilner typing s must

still p erform a runtime check to ensure that its argumentisnot Nil To improve the accuracy of typ e

inference FL typ e inference do es not use the List typ e but rather includes Cons and Nil as distinct typ e

constructors In addition there is a typ e constructor Excttomake exceptions explicit in the typ e The

general typ e of the function s in the FL typ e system is

String Cons Seq s Cons Seq Cons Seq ExcTripleString

where Seq Cons Seq Nil is the set of all sequences Cons Seq is the set of all values that

are not sequences of length at least one TripleX Y Z ConsX ConsY ConsZ Nil and String

ConsChar String Nil This example is typical of the typ es of FL primitive functions The domain

consists of two parts the go o d arguments in this case Cons Seq and the bad arguments in

this case Cons Seq In the range there are the normal results in this case and the

error results The typ e ExcTripleString String Cons Seq is the typ e of an s exception

hs arg xi where x is the argumentto s

Note that the typ e signature is p olymorphic in b oth the go o d and the bad p ortions of the

domain For the go o d arguments Cons Seq is p olymorphic in the typ e of the head of the list For

the bad arguments Cons Seq can b e rened to any subset of the exception pro ducing domain

by instantiating the typ e variable Polymorphism for the exception pro ducing domain is useful for

two reasons First exceptions are intended to b e used lib erally in FL programming and sacricing

the accuracy of typ e inference for exceptions would make exceptions more exp ensive than necessary

since fewer optimizations could b e applied and therefore discourage their use Second accurate typ e

information for exceptions is useful for as it can tell the programmer exactly what typ es of

values may pro duce an exception

The typ e assigned by the FL typ e system to the instance of s in this program is

s ConsInt Seq Int

s by substituting Int for and It is easy to check that this is an instance of the quantied typ e for

for The minimal typ e has the prop ertythat T and T T for all typ es T This typing

proves that s is always applied to a nonempty sequence so no runtime check is required for Nil and

it is immediate that s can never generate an exception

The second example uses a function that computes the last element of a sequence

last h ai where

f def last isseq not isnull isnull tl s last tl g

The function last is dened using the predicate isseq not isnull on the lefthand side of the

sign Recall Section that this predicate is applied to last s argument and if it fails an exception

is returned In this case an exception is returned if last is applied to a nonsequence or hi

The meaning of this expression is a The typ e assigned by the FL typ e system is Char The most

interesting asp ect of the analysis is the typ e assigned to the use of last in the toplevel expression

last X Char where X ConsInt X ConsChar Nil

This typ e shows that last takes a nonempty sequence where the last elementisaChar and returns a

Char The typ e also says that sequence elements other than the last are integers The FL typ e shows

that no runtime exceptions are p ossible so this program can run without runtime typ e checking This

program is not typable in the HindleyMilner system b ecause the argumenttolast is a heterogeneous

sequence

Discussion

FLs lack of a static typ e system has motivated considerable research on new and p owerful typ e systems

that are appropriate for dynamically typ ed languages the FL typ e system is the result of this work The

FL typ e system is a prop er extension of the HindleyMilner system that is able to typ e more programs

more accurately than the HindleyMilner system This is accomplished in a language with no static typ e

constraints so the programmer and compiler are free to use the typ e system or not So what if anything

is the catch This section covers four catches the sp eed of typ e inference understanding typ es runtime

typ e tags and mo dule interfaces

The FL typ e system do es more than the HindleyMilne r system so it is not surprising that it is

slower The asymptotic complexityoftheFLtyp e inference algorithm is double exp onential time while

the HindleyMilner typ e inference algorithm runs in only single exp onential time In practice the FL

typ e system is at least one order of magnitude slower than the HindleyMilner system The FL typ e

system is still fast enough to b e usable but it would b e nice if it were a lot faster it currently takes up

to seconds to analyze a line program

FL typ es are more complex than HindleyMilne r typ es so an FL programmer who wishes to make use

of typ e information must deal with typ es more complex than an ML programmer FL typ es are harder

to read than HindleyMilner typ es primarily b ecause there is not a unique representation of a given typ e

ie manytyp e expressions are equivalent The implementation of the FL typ e system makes use of

identities b etween typ es to simplify the representation of typ es In practice such simplication greatly

improves the readabilityoftyp e expressions

The FL system provides typ e inference as a program analysis to olit is not a required step of

compilation Thus an FL runtime system must carry typ e tags on all data b ecause compiled co de do es

in general p erform runtime typ e checking All existing of functional languages carry

at least some runtime tags on data b ecause existing garbage collection require them There

is however an emerging of tagless garbage collection where compiletime typ es are used at

runtime by the garbage collector to reconstruct tags App If and when tagless garbage collection

algorithms b ecome practical implementations of statically typ ed functional languages will b e able to use

them this option cannot b e exploited in an FL implementation

The last and most serious cost of the FL approachtotyp es is the lackofany mo dule system in FL

parlance a mo dule is a library This is not an inherentproperty of the typ e system FL typ e inference

could accommo date a mechanism for sp ecifying mo dule interfaces Rather the absence of a mo dule

system is the result of a design philosophy that avoids language complexity

FLs mo dule problem can b est b e explained with another p ersp ective on the relationship b etween FL

typ e inference and standard HindleyMilner typ e inference Compare again the HindleyMilner and FL

typ es for s

s List

s Cons Seq Cons Seq ExcTripleString String Cons Seq

Among other things the HindleyMilner typ e says that s must b e used in a context where it is applied

to a list if it is not the compiler rejects the program The FL typ e has no such restrictionthe domain

of s includes all values and so the function can b e used in anycontext If s is in fact applied to a list

then the FL typ e of s is simplied for that instance see the examples in Section Thus FL typ e

inference relies very heavily on information ab out the context in which a function is used in determining

the functions that do not require runtime typ e checking

Unfortunately this use of context information do es not work well with separate compilation and

Consider an FL library A that uses functions dened in library B Library A can

b e compiled using the typ es inferred for functions in B but library B cannot b e compiled knowing that

functions in B are used in the context given by A b ecause library B may b e used at some future p ointby

a new library C that uses B s functions in a dierentcontext If functions in library B were sp ecialized

for library A then B would have to b e recompiled for C in fact B would have to b e recompiled even if A

were mo died In short libraries could not b e compiled separately The current FL solution is to compile

libraries assuming that exp orted functions can b e used in anycontext This allows separate compilation

at the cost of p erforming less program optimization

The programmer could then A metho d for sp ecifying mo dule interfaces would x this problem

describ e the exp ected contexts in which library functions would b e used the compiler would b oth optimize

functions using that information and verify that uses of a function were consistent with its sp ecication

To do this however would require that mo dule sp ecications and typ es b e included in the FL language

denition

InputOutput

Functional programming do es not lend itself readily to interaction with agents indep endent of a program

The canonical problem is IO and sp ecically the problem of writing interactive functional programs

For manyyears there were only two solutions to this problem The convenient solution was not to have

a functional language at all ML Lisp and Scheme are in this category Although all are functional in

the sense that an applicativestyle of programming is encouraged in practice all have state and primitive

op erations that mo dify the state by sideeect The pure solution was to exploit by

treating IO routines as valued stream functions The convenient approach has the advantage

of allowing an unrestricted style of IO programming at the cost of a more complicated underlying

semantics On the other hand the diculty with the explicitly functional approach is that the increased

complexity of a programs functionality b ecomes a notational nuisance which masks the primary purp ose

of the program For example a lazyinteractive program to correct missp elled words in a le using an

up datable dictionary has the primary purp ose of mapping an in file to a corrected file but has

the prop er functionality

hin file dictionary keyboardi hcorrected file dictionary screen rest of keyboardi

Note that the program must b e given keyboard as input to receive resp onses to interactive queries it

puts on screen and it must return the rest of the keyb oard input for use by subsequent programs

The treatment of IO in FL is an attempt to combine the advantages and avoid the problems of

these two approaches by semantically attaching an explicit history comp onent to the functionalityofall

programs and syntactically suppressing consideration of that comp onent The success of this approach

dep ends on the extent to which programmers can use the convenience of treating the history comp onent

implicitlythus keeping their program notations uncluttered and still b e able to write clear programs

Overall FLs IO mechanism has worked out quite well in the FL implementation Only a small

p ortion of the typical FL program uses IO so any reasonable scheme for IO would b e workable The

FL design is esp ecially convenientintwo resp ects First b ecause every function has an implicit history

comp onent it is very easy to add or remove IO from programs without rewriting large sections of

co de If the history comp onentwere explicit then adding IO to one function would require changing

the functionality ie rewriting every function that dep ended directly or indirectly on that function

Second b ecause the history comp onent is abstract and do es not attachany particular semantics to IO

it provides a convenient device for making FL programs work in other ways with the outside world in

e arbitrary C function addition to IO For example in the FL compiler primitive functions that may mak

calls are mo delled as functions that mo dify the history Because the FL compiler is guaranteed to preserve

program semantics including history op erations this has proven to b e a simple waytointegrate existing

C library routines into FL programs

Avalid argument against the FL design is that the p ervasive implicit IO comp onent of the semantics

could seriously handicap program optimization since program transformations must take account of the

p otential for IO anywhere in an FL program In practice this p otential problem is a minor consideration

Because most primitive functions do not dep end on the history comp onent of the semantics and IO is

not used p ervasively in most programs very simple program analysis can identify almost all expressions

that do not p erform IO within these sections of co de more general program transformations apply

Furthermore b ecause a s IO op erations are usually very slow relativetothespeedofamachines

pro cessor largescale optimization on p ortions of programs that do a great deal of IO frequently do es

not improve program p erformance signicantly This last argumentmust b e qualied by the typ e of

IO that is b eing p erformed It certainly holds for interactive programs it is less true of programs with

stringent realtime IO constraints

Since the development of FLs IO system another more general approach to IO in functional

languages has b een discovered This approach known as monadic IO uses higherorder combinators

to hide and control how the history comp onent is threaded through a computation WadPJW

Monadic IO uses a particular monadvariations on the same higherorder combinators can implement

other language features such as exceptions and as monads Essentially FL IO is itself a

particular monad built into the languages denotational semantics The monadic approach takes IO out

of the semantics and makes it available to the programmer which gives monadic IO several advantages

over the FL design First it is more programmablethe history comp onent is not wired into the language

in a particular way and within limits the wiring can b e rearranged by the programmer Second monads

can explicitly delimit the scop e of computations that use IO making program analysis to discover where

IO cannot b e p erformed unnecessary The only disadvantage of monadic IO with resp ect to FL is that

programs must b e structured using a monad to takeadvantageofitThus adding IO to a program

that is not already structured using the IO monad mayinvolve rewriting a large p ortion of the program

Because every FL program has IO built in there is no such cost in FL programming

Exceptions and Order of Evaluation

This section discusses the exp erience with exceptions in FL Because exceptions are inextricably tied with

order of evaluation that topic is addressed here as well Exceptions are one of the successes of FL On

the semantic level it is worth stressing that FLs denotational treatment of exceptions is referentially

transparentFL exceptions are functional On the pragmatic level exceptions have proven very useful

in programming and reasonably ecient to implement

Exceptions help FL programmers in at least twoways First there is a throw and catch style of

programming that is easy with exceptions but dicult to simulate without exceptions The common

scenario is that one wishes to early from a computation in certain circumstances For example in

computing the conjunction of a sequence of truth values there maybenoreasontocontinue after the

rst false value is encountered Signalling an exception ends the computation all that is needed is a

surrounding catch that handles the exception

The second advantage of exceptions in FL is the security that a program cannot terminate without

returning a meaningful value There is nothing implementationdep ende nt ab out FL exceptions Pro

gram optimization or p orting co de to a dierent implementation cannot change the exception pro duced

This prop erty is imp ortant b ecause exceptions playavery large role in helping FL programmers debug

programs recall that all kinds of errorsincluding typ e errorsare exceptions in FL The standard

system exceptions are often informative enough to isolate program bugs quickly An extension that has

b een considered but not implemented in the FL system is to include line numb er information in excep

tions that are the meaning of an entire program The argument for this extension is that it makes nding

where exceptions arise even easier than just having the name of the function the argument against it is a

minor loss of since a programs meaning can now dep end on the textual layout

of the program

A useful p oint of comparison is the situation with runtime exceptions and Lisp When

running Lisp programs it is not uncommon to receive one error message when the program is compiled

and a dierent error message when the program is interpreted Frequently the error message from the

compiled program is on a topic unrelated to the actual problem This sort of b ehavior arises b ecause

optimizing Lisp compilers freely rearrange op erations without regard to preserving errors It also makes

debugging Lisp programs much more dicult than necessary

Another p oint of comparison is ML which incorp orates exceptions in a way quite similar to FL Both

the motivation for and exp erience with exceptions in ML are similar to that of FL App The ma jor

dierence is that exceptions are used uniformly in FL while in ML certain errors are treated as static

typ e errors and others as runtime exceptions

There are semantic and pragmatic arguments for not using exceptions The pragmatic argumentis

twofold rst implementations of exceptions and are exp ensive and second making

exceptions part of program semantics greatly inhibits program optimization These problems are serious

in FL b ecause exceptions are used p ervasively The solution to these problems in the FL implementation

is itself twofold The FL typ e system is able to prove at compiletime that most functions cannot pro duce

exceptions In addition a robust theory of in the presence of exception pro ducing

functions has b een develop ed and implemented in the FL compiler AWW Together these twotools

reduce the cost of FLs p ervasive use of exceptions to a tolerable level

The semantic argument against exceptions is that adding exceptions forces to o much to b e sp ecied

ab out the order of evaluation For example using exceptions a programmer can observe the order in

which a function evaluates its arguments Allowing this kind of programming do es not in teract well with

lazy evaluation this is one of the reasons why lazy functional languages do not have builtin exceptions

At one time this semantic argument carried signicantweight for FLthe language that evolved

into FL was lazy for manyyears HWW Originally FL b ecame strict b ecause it was necessary

to sp ecify an order of evaluation to guarantee that the singlethreaded history comp onent for IO is

handled correctly Exceptions were added to the language later BWW Todaymuch of the original

motivation for strictness has b een removed by the discovery of monadic IO see Section FLs IO

system could b e replaced by monadic IO IO programming would b ecome somewhat more inconvenient

and the language semantics would b e simplied Overall the tradeo maywell b e worthwhile since

IO is a small comp onent of most programs Exceptions to o can b e expressed using a monad so one

might supp ose that exceptions could also b e taken out of the semantics provided as a monad thus further

simplifying FL While this argument has some validity it do es not account for the pragmatic requirements

of FL programming A large part of the security of FL programming comes from the fact that exceptions

are builtin Monads require some extra eort to use so FL programmers would constantly pay a price

for the privilege of o ccasionally programming without exceptions Because of the lack of static typing as a

default programmers who chose not to have exceptions would b e seriously handicapp ed in debugging FL

programs There is of course another alternative drop exceptions and add static typing This alternative

is the design taken in Haskell HWA

After much exp erience with writing functional programs in FL another rationale has emerged for

having a strict language It is often necessary to a functional program to make it run faster

there are always things even an aggressive optimizing compiler cannot do The task of rewriting pro

grams for p erformance is aided greatly by a clear understanding of the order of evaluation Using FLs

simple conventional leftmostinnermost evaluation order it is easy to reason ab out the time and space

complexity of programs In lazy languages very little is known ab out howtodosuch reasoning in general

and programmers writing in lazy languages to dayhave to use considerable ingenuity to write ecient

programs It should b e said that not muchattention has b een given to the problem of writing ecient

lazy functional programs as yet although it is b ecoming an active area of research Lau

Exp erience and Lessons Learned

FL is designed to b e a simple language to learn and to use These desiderata are reected b oth in

the syntax and semantics of FL FLs syntax is very uniform at all levels of programming the only

syntax a programmer must learn is the function denition In contrast most other languages functional

or otherwise often have a separate typ e language mo dule interface language and p erhaps a compiler

pragma language included as part of the programming language Semantically FL manages to b e simple

while still providing supp ort for practical programming features including IO exceptions and user

dened typ es

Among the p eople who have tried programming in FL the ones who like FL most are those who have

little previous programming exp erience F requently these p eople have b een frustrated by the level of

sophistication required to program in conventional imp erative languages such as C FL app eals to naive

programmers b ecause it provides a simple exible programming mo del that can b e learned very quickly

For this group of p eople it is considered an advantage that FL has no static typ e system or mo dule

interface system that must b e learned

At the other end of the sp ectrum users who have substantial programming exp erience in other

functional languages are less enthusiastic ab out FL While these p eople nd FL usable for programming

FL lacks the to ols they are accustomed to esp ecially static typing and a mo dule system Ironically

these omissions are part of what makes FL attractive to inexp erienced programmers In fact b oth

groups haveapoint FLs very simplicitymakes it easy for someone to start programming without b eing

burdened with the daunting task of learning a large language On the other hand FL is to o simple for

sophisticated programmers who want more precise control of the programming pro cess

Details of FLs syntax are annoying to inexp erienced and exp erienced users alike The most common

problems arise from having twosyntactic forms that dier by only a single character which makes it

to o easy to accidentally enteravalid program that means something dierent from what was intended

The lexical structure of FL is to o concisethere should b e more redundancy to help prevent this kind of

programming error

On the other hand exceptions and IO b oth work very well in FL Exceptions in particular turned

out to b e much more imp ortant than originally imagined In a programming language with exceptions

but without static typing exceptions assume the role of the primary debugging assistance provided by

the language This design works reasonably well in practice b ecause in most cases the exception returned

by a primitive function is sucient to isolate a typ e error quickly

FLs IO mechanism provides an unobtrusivemechanism for interacting with agents external to an

FL program The imp ortantlessontobedrawn from FLs IO mechanism is the value of designing IO

into a programming language from the outset The FL denition has a very general IO interface that is

wellintegrated into the language semantics In the FL implementation the IO interface was eventually

used in ways that were not considered during the design for example the IO mechanism provided a

convenient semantically safe way to call foreign functions The careful general initial design of FL paid

o handsomely in this case without the general IO mechanism it would have b een necessary to design

something ad hoc part way through the language implementation and it is unlikely that it would have

worked out as nicely

In many resp ects the design and quality of a language implementation is as imp ortant as the design of

the programming language itself For the FL compiler develop ed at IBM Almaden considerable emphasis

has b een placed on generating co de that is completely faithful to the language semantics This compiler

has b een in use internally for small and large pro jects for several years and at this p oint there is a high

degree of condence in the correctness of the co de pro duced The target language of the compiler is C

Many other compiler pro jects have used C as a target b ecause it is reasonably wellsuited to the role of

a p ortable However p ortability turned out not to b e the greatest b enet of using

C The single greatest b enet to using C as a target is that it is very easy to write programs that inter

op erate with C routines in addition one immediately has access to the vast array of C library routines

already in existence

Somewhat surprisingly compatibility with C is the key that has made it feasible for users to write in

FL Writing a large application from scratch is hard work in any language it is particularly uninviting

when signicant p ortions of the application are already implemented in another language Making it

p ossible for p eople to use FL without giving up their favorite C libraries has made giving FL a try a

much more attractive and viable prosp ect

It was recognized from the outset of the FL compiler eort that program optimization would play

a critical role in generating go o d co de from FL programs This has indeed proven to b e the case The

FL compiler p erforms a great deal of program analysis and transformation includin g many standard

optimizations as well as some unique to FL Among the latter the most imp ortant is the combination

of typ e inference and program transformation aimed at reducing the overhead of runtime typ e checking

and exception handling see Section

The most serious aw in the FL compiler is a direct result of the heavy emphasis on program analysis

and optimization The FL compiler is slow with most of the time sp ent in the backend phases In this

resp ect FL is in go o d company with other functional language implementations some but certainly not

all of which are slower than the FL compiler Unfortunately is a scarce resource and must

b e treated as such In the FL compiler it has b een necessary to insert a fast path for compilation

that bypasses all of the analysis and optimization and enables programs to b e compiled in a few seconds

Almost all FL development is done using the nonoptimizing version of the compiler optimization is only

used in the nal stages of As functional programming b ecomes more p opular and

mainstream it will b e necessary to place more emphasis on writing compilers for functional languages

with go o d interactive p erformance

Acknowledgements

The authors are grateful to all of the p eople who haveworked on the design and implementation of FL

John Backus sup ervised and supp orted all of the design and much of the implementation Peter Lucas

also contributed a great deal to the FL denition and compiler In roughly chronological order Tim

Winkler Bill Griswold Thom Linden Paul Tucker Brian Murphy Brennan Gaunce David Evans and

TK Lakshman all wrote substantial p ortions of the FL compiler and Finally the authors

are indebted to Ray Strong and Danny Dolev for illustrating by example how to program large systems

in FL

References

App A App el Runtime tags arent necessary Lisp and Symbolic Computation

App A App el A critique of Standard ML Journal of Functional Programming to

app ear

A Aiken and E Wimmers Typ e inclusion constraints and typ e inference In Proceedings AW

of the ConferenceonFunctional Programming Languages and Architecture

pages Cop enhagen Denmark June

AWL A Aiken E Wimmers and TK Lakshman Soft typing with conditional typ es In Twenty

First Annual ACM Symposium on Principles of Programming Languages pages

Portland Oregon January

AWW A Aiken J H Williams and E L Wimmers Program transformation in the presence of

errors In Seventeenth Annual ACM Symposium on Principles of Programming Languages

pages January

Bac J Backus Can programming b e lib erated from the von Neumann style A functional style

and its algebra of programs of the ACM August

Bac J Backus From function level semantics to program transformation and optimization

Technical Rep ort RJ IBM

BWW J Backus J H Williams and E L Wimmers The FL language manual Technical Rep ort

RJ IBM

BWW J Backus J H Williams E L Wimmers P Lucas and A Aiken The FL language

manual parts and Technical Rep ort RJ IBM

BWW J Backus J H Williams and E L Wimmers An intro duction to the programming

language FL In D Turner editor Research Topics in Functional Programming pages

AddisonWesley June

DM L Damas and R Milner Principle typ eschemes for functional programs In Ninth Annual

ACM Symposium on Principles of Programming Languages pages January

HMT R Harp er R Milner and M Tofte The denition of standard MLversion Technical

Rep ort ECFSLF CS Lab oratory for Foundations of Universityof

Edinburgh

HWA P Hudak PWadler Arvind B Boutel J Fairbairn J Fasel J Hughes T Johnsson

D Kieburtz S P Jones R Nikhil M Reeve D Wise and J Young Rep ort on the

functional programming language Haskell Technical Rep ort DCSRR Yale University

December

HWW J Halp ern J Williams and E Wimmers Go o d rewrite strategies for FP In Thirteenth

Annual ACM Symposium on Principles of Programming Languages pages January

HWW J Halp ern J Williams and E Wimmers Completeness of rewrite rules and rewrite strate

gies for FP Journal of the ACM January

HWWW J Halp ern J Williams E Wimmers and T Winkler Denotational semantics and rewrite

rules for FP In Twelfth Annual ACM Symposium on Principles of Programming Languages

pages January

Lau J Launchbury A natural semantics for lazy evaluation In Twentieth Annual ACM Sym

posium on Principles of Programming Languages pages January

PJW S L Peyton Jones and PWadler Imp erative functional programming In Nineteenth

Annual ACM Symposium on Principles of Programming Languages pages January

Sto J E Stoy Denotational Semantics The ScottStrachey Approach to Programming Language

Theory The MIT Press Cambridge MA

Wad PWadler Comprehending monads In Proceedings of the ACM Conference on Lisp and

Functional Programming June

Wila J Williams Notes on the FP style of functional programming In Functional Programming

and its Applications Cambridge University Press January

Wilb J Williams On the development of the algebra of functional programs ACM Transactions

on Pro gramming Languages and Systems Octob er

WW J H Williams and E L Wimmers Sacricing simplicity for convenience Where do you

draw the line In Fifteenth Annual ACM Symposium on Principles of Programming Lan

guages pages January