164
1 CS 538 Spring 2003 © CS 538 Introduction to the Theory and Design of Programming Languages Charles N. Fischer Spring 2003 http://www.cs.wisc.edu/~fischer/cs538.html 2 CS 538 Spring 2003 © Class Meets Mondays, Wednesdays & Fridays, 11:00 — 11:50 1227 Engineering Hall Instructor Charles N. Fischer 5397 Computer Sciences Telephone: 262-6635 E-mail: [email protected] Office Hours: 10:30 - Noon, Tuesdays & Thursdays, or by appointment 3 CS 538 Spring 2003 © Teaching Assistant Manoj Plakal 5394 Computer Sciences Telephone: 262-6612 E-mail: [email protected] Office Hours: 3:00-4:00, Mondays, Wednesdays & Fridays, or by appointment 4 CS 538 Spring 2003 © Key Dates February 21: Homework #1 (tentative) March 14: Programming Assignment #1 - Scheme (tentative) March 28: Midterm Exam (tentative) April 11: Programming Assignment #2 - Standard ML (tentative) April 28: Programming Assignment #3 - Prolog (tentative) May 9: Programming Assignment #4 - Pizza, C# and Python May 12: Final Exam 2:45pm-4:45pm

pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

1CS 538 Spring 2003©

CS 538

Introduction to the Theory andDesign of Programming

Languages

Charles N. Fischer

Spring 2003

http://www.cs.wisc.edu/~fischer/cs538.html

2CS 538 Spring 2003©

Class MeetsMondays, Wednesdays & Fridays,11:00 — 11:501227 Engineering Hall

InstructorCharles N. Fischer5397 Computer SciencesTelephone: 262-6635E-mail: [email protected] Hours:

10:30 - Noon, Tuesdays &Thursdays, or by appointment

3CS 538 Spring 2003©

Teaching AssistantManoj Plakal5394 Computer SciencesTelephone: 262-6612E-mail: [email protected] Hours:

3:00-4:00, Mondays, Wednesdays & Fridays, or by appointment

4CS 538 Spring 2003©

Key Dates• February 21: Homework #1 (tentative)• March 14: Programming Assignment #1 -

Scheme (tentative)• March 28: Midterm Exam (tentative)• April 11: Programming Assignment #2 -

Standard ML (tentative)• April 28: Programming Assignment #3 -

Prolog (tentative)• May 9: Programming Assignment #4 -

Pizza, C# and Python• May 12: Final Exam 2:45pm-4:45pm

Page 2: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

5CS 538 Spring 2003©

Class Text• Required text:

“Foundations of ProgrammingLanguages,”Seyed Roosta,Brooks/Cole, 2003.

• Suggested supplemental Class Text:“Modern Programming Languages,”Adam Webber,Franklin, Beedle & Associates, 2003.

• Handouts and Web-based reading willalso be used.

6CS 538 Spring 2003©

Reading Assignment• Roosta: Chapters 1-3 (as background)

• Webber: Chapters 1, 10, 18 (asbackground)

Class Notes• The transparencies used for each lecture

will be made available prior to, and after,that lecture on the class Web page(under the “Lecture Nodes” link).

7CS 538 Spring 2003©

Instructional ComputersDepartmental Unix Machines (nova1-nova60) have been assigned to CS538. All necessary compiler,interpreters and tools will be loadedonto these machines.

You may also use your own PC orworkstation. It will be yourresponsibility to load needed software(instructions on where to find neededsoftware are included on the classweb page).

The Systems Lab teaches brieftutorials on Unix if you are unfamiliarwith that OS.

8CS 538 Spring 2003©

Academic Misconduct Policy• You must do your own assignments —

no copying or sharing of solutions.

• You may discuss general concepts andIdeas.

• All cases of misconduct must be reportedto the Dean’s office.

• Penalties may be severe.

Page 3: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

9CS 538 Spring 2003©

Program & Homework LatePolicy• An assignment may be handed in one,

two, or three class periods late, but notany later.

• One late period will be debited 10%,two late periods will be debited 20%,three late periods will be debited 30%.

• All students are given 4 “free” lateperiods. That is, the first 40% in latedebits will be automatically forgiven.

• Your 4 free late periods my be used atany time, and in any combination.

10CS 538 Spring 2003©

Approximate Grade WeightsHomework 1 10%Program 1 - Scheme 16%Program 2 - ML 16%Program 3 - Prolog 12%Program 4 - Pizza, C# & Python

6%Midterm Exam 20%Final Exam (non-cumulative) 20%

11CS 538 Spring 2003©

Programming Languages to beConsidered in Detail1. Scheme

A modern variant of Lisp.A Functional Language: Functions are“first class” data values.Dynamically Typed: A variable’s typemay change during execution; notype declarations are needed.All memory allocation anddeallocation is automatic.Primary data structures, lists andnumbers, are unlimited in size andmay grow without bound.Continuations provide a novel way tosuspend and “re-execute”computations.

12CS 538 Spring 2003©

2. ML (“Meta Language”)Strong, compile-time type checking.Types are determined by inferencerather than declaration.Polymorphic (one functiondeclaration can be used with manydifferent types).Pattern-directed programming (youdefine patterns that are automaticallymatched during a call).Typed exceptions are provided.Abstract data types, withconstructors, are included.

Page 4: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

13CS 538 Spring 2003©

3. Prolog (Programming in Logic)Programs are Facts and Rules.Programmers are concerned withdefinition, not execution.Execution order is automaticallydetermined.

4. PizzaExtends a popular Object-orientedlanguage, Java, to include• Parametric polymorphism (similar to

C++’s templates)

• First-class functional objects

• Algebraic data types, includingpatterns.

14CS 538 Spring 2003©

5. C#This is Microsoft’s answer to Java. Inmost ways it is very similar to Java,with some C++ concepts reintroducedand some useful additions.• Events and delegates are included to

handle asynchronous actions (likekeyboard or mouse actions).

• Properties allow user-defined readand write actions for fields.

• Indexers allow objects other thanarrays to be indexed.

• Collection classes may be directlyenumerated:foreach (int i in array) ...

• Structs and classes co-exist and maybe inter-converted (boxed andunboxed).

15CS 538 Spring 2003©

• Enumerations, operator overloadingand rectangular arrays are provided.

• Reference, out and variable-lengthparameter lists are allowed.

6. PythonA simple, efficient scripting languagethat quickly builds new programs outof existing applications and libraries.Cleanly includes objects.Scales nicely into larger applications.

16CS 538 Spring 2003©

Evolution of ProgrammingLanguages

In the beginning, ...programs were written in absolutemachine code—a sequence of bitsthat encode machine instructions.Example:

340200050000000c3c011001ac220000

This form of programming is• Very detailed

• Very tedious

• Very error-prone

• Very machine specific

Page 5: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

17CS 538 Spring 2003©

Symbolic AssemblersAllow use of symbols for operationcodes and labels.Example:

li $v0,5syscallsw $v0,a

Far more readable, but still verydetailed, tedious and machine-specific.Types are machine types.Control structures are conditionalbranches.Subprograms are blocks of code calledvia a “subroutine branch” instruction.All labels are global.

18CS 538 Spring 2003©

Fortran (Formula Translator)Example:

do 10 i=1,100

10 a(i)=0

Developed in the mid-50s.A major step forward:• Programming became more “problem

oriented” and less “machine oriented.”• Notions of control structures (ifs and

do loops) were introduced.• Subprograms, calls, and parameters

were made available.• Notions of machine independence were

introduced.• Has evolved into more modern variants,

including Fortran 77, Fortran 90 andHPF (High Performance Fortran).

19CS 538 Spring 2003©

Cobol (Common BusinessOriented Language)

Example:multiply i by 3 giving j.move j to k.write line1 after advancing1 lines.

Developed in the early 60s.The first widely-standardizedprogramming language,Once very widely used in thecommercial world; still important.Wordy in structure; designed for non-scientific users.Raised the issue of who shouldprogram and how importantreadability and maintainability are.

20CS 538 Spring 2003©

Algol 60 (Algorithmic Language)Example:

real procedure cheb(x,n);value x,n;real x; integer n;cheb := if n = 0 then 1 else if n = 1 then x else 2 × x × cheb(x,n-1)-cheb(x,n-2);

Developed about 1960.Direct precursor of Pascal, C, C++ andJava.Introduced many ideas now in wideuse:• Blocks with local declarations and

scopes.

• Nested declarations and controlstructures.

Page 6: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

21CS 538 Spring 2003©

• Parameter passing

• Automatic recursion.But,• I/O wasn’t standardized.

• IBM promoted Fortran and PL/I.

22CS 538 Spring 2003©

Lisp (List Processing Language)Example:

((lambda (x) (* x x)) 10)

Developed in the early 60s.A radical departure from earlierprogramming languages.Programs and data are represented ina uniform list format.Types are a property of data values,not variables or parameters.A program can build and run newfunctions as it executes.Data values were not fixed in size.Memory management was automatic.A formal semantics was developed todefine precisely what a programmeans.

23CS 538 Spring 2003©

Simula 67 (Simulation Algol)Example:

Class Rectangle (Width, Height);Real Width, Height;Boolean Procedure IsSquare; IsSquare := Width=Height;End of Rectangle;

Developed about 1967.Introduced the notion of a class (forsimulation purposes).Included objects, a garbage collector,and notions of extending a class.C++ was originally C with classes (asSimula was Algol with classes).

24CS 538 Spring 2003©

C and C++C was developed in the early 70’s;C++ in the mid-80s.These languages have a concise,expressive syntax; they generate highquality code sufficient forperformance-critical applications.C, along with Unix, provided theviability of platform-independentlanguages and applications.C and C++ allow programmers a greatdeal of freedom in bending andbreaking rules.Raise the issue of whether onelanguage can span both novice andexpert programmers.

Page 7: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

25CS 538 Spring 2003©

Interesting issue—if most statementsand expressions are meaningful, canerrors be readily detected?

if (a=b)

a=0;

else a = 1;

26CS 538 Spring 2003©

JavaDeveloped in the late 90s.Cleaner object-oriented languagethan C++.Introduced notions of dynamicloading of class definitions across theWeb.Much stronger emphasis on secureexecution and detection of run-timeerrors.Extended notions of platformindependence to systemindependence.

27CS 538 Spring 2003©

What Drives Research intoNew Programming Languages?Why isn’t C or C++ or C+++ enough?1. Curiosity

What other forms can a programminglanguage take?What other notions of programmingare possible?

2. ProductivityProcedural languages, including C,C++ and Java, are very detailed.Many source lines imply significantdevelopment and maintenanceexpenses.

28CS 538 Spring 2003©

3. ReliabilityToo much low-level detail inprograms greatly enhances thechance of minor errors. Even minorerrors can raise significant problemsin applications.

4. SecurityComputers are entrusted with ever-increasing responsibilities. How canwe know that a program is safe andreliable enough to trust?

5. Execution speedProcedural languages are closely tiedto the standard sequential model ofinstruction execution. We may needradically different programmingmodels to fully exploit parallel anddistributed computers.

Page 8: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

29CS 538 Spring 2003©

Desirable Qualities in aProgramming Language

Theoretically, all programminglanguages are equivalent (Why?)If that is so, what properties aredesirable in a programming language?

30CS 538 Spring 2003©

• It should be easy to use.Programs should be easy to read andunderstand.Programs should be simple to write,without unexpected pitfalls.It should be orthogonal, providingonly one way to do each step orcomputation.Its notation should be natural for theapplication being programed.

• The language should supportabstraction.

You can’t anticipate all needed datastructures and operations, so addingnew definitions easily and efficientlyshould be allowed.

31CS 538 Spring 2003©

• The language should support testing,debugging and verification.

• The language should have a gooddevelopment environment.

Integrated editors, compilers,debuggers, and version control are abig plus.

• The language should be portable,spanning many platforms and operatingsystems.

32CS 538 Spring 2003©

• The language should be inexpensive touse:

Execution should be fast.Memory needs should be modest.Translation should be fast andmodular.Program creation and testing shouldbe easy and cheap.Maintenance should not be undulycumbersome.Components should be reusable.

Page 9: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

33CS 538 Spring 2003©

Programming ParadigmsProgramming languages naturally fallinto a number of fundamental stylesor paradigms.

Procedural LanguagesMost of the widely-known andwidely-used programming languages(C, Fortran, Pascal, Ada, etc.) areprocedural in nature.Programs execute statement bystatement, reading and modifying ashared memory.This programming style closelymodels conventional sequentialprocessors linked to a random accessmemory (RAM).

34CS 538 Spring 2003©

Question:Given

a = a + 1;

if (a > 10) b = 10; else b = 15; a = a * b;

Why can’t 5 processors each executeone line to make the program run 5times faster?

35CS 538 Spring 2003©

Functional LanguagesLisp, Scheme and ML are functional innature.Programs are expressions to beevaluated.Language design aims to minimizeside-effects, including assignment.Alternative evaluation mechanismsare possible, including

Lazy (Demand Driven)Eager (Data Driven or Speculative)

36CS 538 Spring 2003©

Object-Oriented LanguagesC++, Java, Smalltalk, Pizza andPython are object-oriented.Data and functions are encapsulatedinto Objects.Objects are active, have persistentstate, and uniform interfaces(messages or methods).Notions of inheritance and commoninterfaces are central.All objects that provide the sameinterface can be treated uniformly. InJava you can print any object thatprovides the toString method. Youcan iterate through the elements ofany Java object that implements theEnumeration interface.

Page 10: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

37CS 538 Spring 2003©

Subclassing allows to you extend orredefine part of an object’s behaviorwithout reprogramming all of theobject’s definition. Thus in Java, youcan take a Hashtable class (which isfairly elaborate) and create a subclassin which an existing method (liketoString ) is redefined, or newoperations are added.

38CS 538 Spring 2003©

Logic Programming LanguagesProlog notes that most programminglanguages address both the logic of aprogram (what is to be done) and thecontrol flow of a program (how to dowhat you want).A logic programming language, likeProlog, lets programmers focus on aprogram’s logic without concern forcontrol issue.These languages have no real controlstructures, and little notion of “flowof control.”What results are programs that areunusually succinct and focused.

39CS 538 Spring 2003©

Example:inOrder( [] ).inOrder( [ _ ] ).inOrder([a,b|c]) :- (a<b),

inOrder([b|c]).

This is a complete, executablefunction that determines if a list is inorder. It is naturally polymorphic, andis not cluttered with declarations,variables or explicit loops.

40CS 538 Spring 2003©

Review of Concepts fromProcedural ProgrammingLanguages

Declarations/Scope/Lifetime/BindingStatic/Dynamic

• Identifiers are declared, either explicitlyor implicitly (from context of first use).

• Declarations bind type and kindinformation to an identifier. Kindspecifies the grouping of an identifier(variable, label, function, type name,etc.)

• Each identifier has a scope (or range) ina program—that part of the program inwhich the identifier is visible (i.e., maybe used).

Page 11: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

41CS 538 Spring 2003©

• Data objects have a lifetime—the span oftime, during program execution, duringwhich the object exists and may be used.

• Lifetimes of data objects are often tiedto the scope of the identifier thatdenotes them. The objects are createdwhen its identifier’s scope is entered, andthey may be deleted when the identifier’sscope is exited. For example, memory forlocal variables within a function isusually allocated when the function iscalled (activated) and released when thecall terminates.In Java, a method may be loaded intomemory when the object it is a memberof is first accessed.

42CS 538 Spring 2003©

Properties of an identifier (and theobject it represents) may be set at• Compile-time

These are static properties as they donot change during execution.Examples include the type of avariable, the value of a constant, theinitial value of a variable, or the bodyof a function.

• Run-timeThese are dynamic properties.Examples include the value of avariable, the lifetime of a heap object,the value of a function’s parameter,the number of times a while loopiterates, etc.

43CS 538 Spring 2003©

Example: In Fortran• The scope of an identifier is the whole

program or subprogram.

• Each identifier may be declared onlyonce.

• Variable declarations may be implicit.(Using an identifier implicitly declares itas a variable.)

• The lifetime of data objects is the wholeprogram.

44CS 538 Spring 2003©

Block Structured Languages• Include Algol 60, Pascal, C and Java.

• Identifiers may have a non-global scope.Declarations may be local to a class,subprogram or block.

• Scopes may nest, with declarationspropagating to inner (contained) scopes.

• The lexically nearest declaration of anidentifier is bound to uses of thatidentifier.

Page 12: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

45CS 538 Spring 2003©

Binding of an identifier to itscorresponding declaration is usuallystatic (also called lexical), thoughdynamic binding is also possible.Static binding is done prior toexecution—at compile-time.Example (drawn from C):

int x,z;void A() {

float x,y; print(x,y,z);

}void B() { print (x,y,z)

}

floatfloat

int

int

intundeclared

46CS 538 Spring 2003©

Block Structure Concepts• Nested Visibility

No access to identifiers outside theirscope.

• Nearest Declaration AppliesStatic name scoping.

• Automatic Allocation and Deallocationof Locals

Lifetime of data objects is bound tothe scope of the Identifiers thatdenote them.

47CS 538 Spring 2003©

Variations in these rules of namescoping are possible.For example, in Java, the lifetime ofall class objects is from the time oftheir creation (via new) to the lastvisible reference to them.Thus ... Object O; ...creates an object reference but doesnot allocate any memory space for O.You need ... Object O = new Object(); ...to actually create memory space forO.

48CS 538 Spring 2003©

Dynamic ScopingAn alternative to static scoping isdynamic scoping, which was used inearly Lisp dialects (but not in Scheme,which is statically scoped).Under dynamic scoping, identifiersare bound to the dynamically closestdeclaration of the identifier. Thus ifan identifier is not locally declared,the call chain (sequence of callers) isexamined to find a matchingdeclaration.

Page 13: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

49CS 538 Spring 2003©

Example: int x;

void print() {

write(x); }

main () {

bool x;

print();

}

Under static scoping the x written inprint is the lexically closestdeclaration of x , which is as an int .Under dynamic scoping, since printhas no local declaration of x , print ’scaller is examined. Since main callsprint , and it has a declaration of xas a bool , that declaration is used.

50CS 538 Spring 2003©

Dynamic scoping makes type checkingand variable access harder and morecostly than static scoping. (Why?)However, dynamic scoping does allowa notion of an “extended scope” inwhich declarations extend tosubprograms called within that scope.Though dynamic scoping may seen abit bizarre, it is closely related tovirtual functions used in C++ andJava.

51CS 538 Spring 2003©

Virtual FunctionsA function declared in a class, C, maybe redeclared in a class derived fromC. Moreover, for uniformity ofredeclaration, it is important that allcalls, including those in methodswithin C, use the new declaration.Example: class C {

void DoIt()(PrintIt();} void PrintIt() {println(“C rules!”);} } class D extends C { void PrintIt() {println(“D rules!”);} void TestIt() {DoIt();} } D dvar = new D(); dvar.TestIt();

D rules! is printed.

52CS 538 Spring 2003©

Scope vs. LifetimeIt is usually required that the lifetimeof a run-time object at least coverthe scope of the identifier. That is,whenever you can access an identifier,the run-time object it denotes betterexist.But,it is possible to have a run-timeobject’s lifetime exceed the scope ofits identifier. An example of this isstatic or own variables.

Page 14: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

53CS 538 Spring 2003©

In C:void p() {

static int i = 0;

print(i++);

}

Each call to p prints a different valueof i (0, 1, ...) Variable i retains itsvalue across calls.Some languages allow an explicitbinding of an identifier for a fixedscope:

A declaration may appear wherever astatement or expression is allowed.Limited scopes enhance readability.

Letid = val

in statementsend;

{ type id = val; statements

}

54CS 538 Spring 2003©

Structs vs. BlocksMany programming languages,including C, C++, C#, Pascal and Ada,have a notion of grouping datatogether into structs or records.For example:

struct complex { float re, im; }

There is also the notion of groupingstatements and declarations intoblocks:

{ float re, im;

re = 0.0; im = 1.0;

}

55CS 538 Spring 2003©

Blocks and structs look similar, butthere are significant differences:Structs are data,• As originally designed, structs contain

only data (no functions or methods).

• Structs can be dynamically created, inany number, and included in otherdata structures (e.g., in an array ofstructs).

• All fields in a struct are visibleoutside the struct.

56CS 538 Spring 2003©

Blocks are code,• They can contain both code and data.

• Blocks can’t be dynamically createdduring execution; they are “builtinto” a program.

• Locals in a block aren’t visible outsidethe block.

By adding functions and initializationcode to structs, we get classes—a niceblend of structs and blocks.For example:class complex{

float re, im;

complex (float v1, float v2){

re = v1; im = v2; }

}

Page 15: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

57CS 538 Spring 2003©

Classes• Class objects can be created as needed,

in any number, and included in otherdata structure.

• They include both data (fields) andfunctions (methods).

• They include mechanisms to initializethemselves (constructors) and to finalizethemselves (destructors).

• They allow controlled access to members(private and public declarations).

58CS 538 Spring 2003©

Type Equivalence in ClassesIn C, C++ and Java, instances of thesame struct or class are type-equivalent, and mutually assignable.For example:class MyClass { ... }MyClass v1, v2;v1 = v2; // Assignment is OK

We expect to be able to assign valuesof the same type, including classobjects.However, sometimes a class models adata object whose size or shape is setupon creation (in a constructor).Then we may not want assignment tobe allowed.

59CS 538 Spring 2003©

class Point { int dimensions; float coordinates[]; Point () { dimensions = 2; coordinates = new float[2]; } Point (int d) { dimensions = d; coordinates = new float[d]; } } Point plane = new Point(); Point solid = new Point(3);

plane = solid; //OK in Java

This assignment is allowed, eventhough the two objects representpoints in different dimensions.

60CS 538 Spring 2003©

SubtypesIn C++, C# and Java we can createsubclasses—new classes derived froman existing class.We can use subclasses to create newdata objects that are similar (sincethey are based on a common parent),but still type-inequivalent.Example:

class Point2 extends Point {

Point2() {super(2); } } class Point3 extends Point { Point3() {super(3); } } Point2 plane = new Point2(); Point3 solid = new Point3();

plane = solid; //Illegal in Java

Page 16: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

61CS 538 Spring 2003©

Parametric PolymorphismWe can create distinct subclassesbased on the values passed toconstructors. But sometimes we wantto create subclasses based on distincttypes, and types can’t be passed asparameters. (Types are not values, butrather a property of values.)We see this problem in Java, whichtries to create general purpose datastructures by basing them on theclass Object . Since any object can beassigned to Object (all classes mustbe a subclass of Object ), this works—at least partially.

62CS 538 Spring 2003©

class LinkedList { Object value; LinkedList next; Object head() {return value;}

LinkedList tail(){return next;} LinkedList(Object O) { value = O; next = null;} LinkedList(Object O, LinkedList L){ value = O; next = L;}}

Using this class, we can create alinked list of any subtype of Object .But,• We can’t guarantee that linked lists

are type homogeneous (contain only asingle type).

• We must cast Object types back intotheir “real” types when we extract listvalues.

63CS 538 Spring 2003©

• We must use wrapper classes likeInteger rather than int (becauseprimitive types like int aren’tobjects, and aren’t subclass ofObject ).

For example, to use LinkedList tobuild a linked list of int s we do thefollowing:

LinkedList l = new LinkedList(new Integer(123));

int i = ((Integer) l.head()).intValue();

This is pretty clumsy code. We’dprefer a mechanism that allows us tocreate a “custom version” ofLinkedList , based on the type wewant the list to contain.

64CS 538 Spring 2003©

We can’t just call something likeLinkedList(int) orLinkedList(Integer) because

types can’t be passed as parameters.Parametric polymorphism is thesolution. Using this mechanism, wecan use type parameters to build a“custom version” of a class from ageneral purpose class.C++ allows this using its templatemechanism. Pizza, an extension ofJava, also allows type parameters.In both languages, type parametersare enclosed in “angle brackets” (e.g.,LinkedList<T> passes T, a type, tothe LinkedList class).

Page 17: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

65CS 538 Spring 2003©

In Pizza we haveclass LinkedList<T> { T value; LinkedList<T> next; T head() {return value;} LinkedList<T> tail() { return next;} LinkedList(T O) { value = O; next = null;} LinkedList(T O,LinkedList<T> L) {value = O; next = L;}}

LinkedList<int> l = new LinkedList(123);

int i = l.head();

66CS 538 Spring 2003©

Overloading and Ad-hocPolymorphism

Classes usually allow overloading ofmethod names, if only to supportmultiple constructors.That is, more than one methoddefinition with the same name isallowed within a class, as long as themethod definitions differ in thenumber and/or types of theparameters they take.For example,class MyClass {

int f(int i) { ... }

int f(float g) { ... }

int f(int i, int j) { ... }

}

67CS 538 Spring 2003©

Overloading is sometimes called “adhoc” polymorphism, because, to theprogrammer, it appears that onemethod can take a variety of differentparameter types. This isn’t truepolymorphism because the methodshave different bodies; there is nosharing of one definition amongdifferent parameter types. There is noguarantee that the differentdefinitions do the same thing, eventhough they share a common name.

68CS 538 Spring 2003©

Issues in OverloadingThough many languages allowoverloading, few allow overloadedmethods to differ only on their resulttypes. (Neither C++ nor Java allowthis kind of overloading, though Adadoes). For example,class MyClass {

int f() { ... }

float f() { ... }

}

is illegal. This is unfortunate, sincemethods with the same name andparameters, but different result types,could be used to automaticallyconvert result values to the typedemanded by the context of call.

Page 18: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

69CS 538 Spring 2003©

Why is this form of overloadingusually disallowed?It’s because overload resolution(deciding which definition to use)becomes much harder. Considerclass MyClass { int f(int i, int j) { ... } float f(float i, float j) { ... } float f(int i, int j) { ... }}

inint a = f( f(1,2), f(3,4) );

which definitions of f do we use ineach of the three calls? Getting thecorrectly answer can be tricky, thoughsolution algorithms do exist.

70CS 538 Spring 2003©

Operator OverloadingSome languages, like C++ and C#,allow operators to be overloaded. Youmay add new definitions to existingoperators, and use them on your owntypes. For example, class MyClass {

int i;

public:

int operator+(int j) {

return i+j; }

}

MyClass c;

int i = c+10;

int j = c.operator+(10);

int k = 10+c; // Illegal!

71CS 538 Spring 2003©

The expression 10+c is illegal becausethere is no definition of + for thetypes int and MyClass& . We cancreate one by using C++’s friendmechanism to insert a definition intoMyClass that will have access toMyClass ’s private data: class MyClass {

int i;

public:

int operator+(int j) {

return i+j; } friend int operator+ (int j, MyClass& v){

return j+v.i; }

}

MyClass c;

int k = 10+c; // Now OK!

72CS 538 Spring 2003©

C++ limits operator overloading toexisting predefined operators. A fewlanguages, like Algol 68 (a successorto Algol 60, developed in 1968),allow programmers to define brandnew operators.In addition to defining the operatoritself, it is also necessary to specifythe operator’s precedence (whichoperator is to be applied first) and itsassociativity (does the operatorassociate from left to right, or rightto left, or not at all). Given this extradetail, it is possible to specifysomething like

op +++ prec = 8; int op +++(int& i, int& j) { return (i++)+(j++); }

(Why is int& used as the parametertype rather than int ?)

Page 19: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

73CS 538 Spring 2003©

Parameter BindingAlmost all programming languageshave some notion of binding an actualparameter (provided at the point ofcall) to a formal parameter (used inthe body of a subprogram).There are many different, andinequivalent, methods of parameterbinding. Exactly which is useddepends upon the programminglanguage in question.Parameter Binding Modes include:• Value: The formal parameter

represents a local variable initializedto the value of the correspondingactual parameter.

74CS 538 Spring 2003©

• Result: The formal parameterrepresents a local variable. Its finalvalue, at the point of return, is copiedinto the corresponding actualparameter.

• Value/Result: A combination of thevalue and results modes. The formalparameter is a local variableinitialized to the value of thecorresponding actual parameter. Theformal’s final value, at the point ofreturn, is copied into thecorresponding actual parameter.

• Reference: The formal parameter is apointer to the corresponding actualparameter. All references to theformal parameter indirectly accessthe corresponding actual parameterthrough the pointer.

75CS 538 Spring 2003©

• Name: The formal parameterrepresents a block of code(sometimes called a thunk) that isevaluated to obtain the value oraddress of the corresponding actualparameter. Each reference to theformal parameter causes the thunk tobe reevaluated.

• Readonly (sometimes called Const):Only reads of the formal parameterare allowed. Either a copy of theactual parameter’s value, or itsaddress, may be used.

76CS 538 Spring 2003©

What Parameter Modes doProgramming Languages Use?• C: Value mode except for arrays where a

pointer to the start of the array ispassed.

• C++: Allows reference as well as valuemodes. E.g.,

int f(int a, int& b)

• C#: Allows result (out) as well asreference and value modes. E.g.,

int g(int a, out int b)

• Java: Scalar types (int , float , char ,etc.) are passed by value; objects arepassed by reference.

• Fortran: Reference (even for constants!)

• Ada: Value/result, reference, andreadonly are used.

Page 20: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

77CS 538 Spring 2003©

Examplevoid p(value int a, reference int b, name int c) { a=1; b=2; print(c)}int i=3, j=3, k[10][10];p(i,j,k[i][j]);

What element of k is printed?• The assignment to a does not affect

i , since a is a value parameter.

• The assignment to b does affect j ,since b is a reference parameter.

• c is a name parameter, so it isevaluated whenever it is used. In theprint statement k[i][j] is printed.At that point i =3 and j =2, sok[3][2] is printed.

78CS 538 Spring 2003©

Why are there so ManyDifferent Parameter Modes?

Parameter modes reflect differentviews on how parameters are to beaccessed, as well as different degreesof efficiency in accessing and usingparameters.• Call by value protects the actual

parameter value. No matter what thesubprogram does, the parameter can’tbe changed.

• Call by reference allows immediateupdates to the actual parameter.

• Call by readonly protects the actualparameter and emphasizes the“constant” nature of the formalparameter.

79CS 538 Spring 2003©

• Call by value/result allows actualparameters to change, but treats acall as a single step (assign parametervalues, execute the subprogram’sbody, update parameter values).

• Call by name delays evaluation of anactual parameter until it is actuallyneeded (which may be never).

80CS 538 Spring 2003©

Call by NameCall by name is a special kind ofparameter passing mode. It allowssome calls to complete that otherwisewould fail. Consider

f(i,j/0)

Normally, when j/0 is evaluated, adivide fault terminates execution. Ifj/0 is passed by name, the division isdelayed until the parameter is needed,which may be never.Call by name also allows programmersto create some interesting solutionsto hard programming problems.Consider the conditional expressionfound in C, C++, and Java:

(cond?value1:value2)

Page 21: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

81CS 538 Spring 2003©

What if we want to implement this asa function call:

condExpr(cond,value1,value2) {

if (cond) return value1; else return value2; }

With most parameter passing modesthis implementation won’t work!(Why?)But if value1 and value2 are passedby name, the implementation iscorrect.

82CS 538 Spring 2003©

Call by Name and LazyEvaluation

Call by name has much of the flavorof lazy evaluation. With lazyevaluation, you don’t compute a valuebut rather a suspension—a functionthat will provide a value when called.This can be useful when we need tocontrol how much of a computationis actually performed.Consider an infinite list of integers.Mathematically it is represented as 1, 2, 3, ...How do we compute a data structurethat represents an infinite list?

83CS 538 Spring 2003©

The obvious computationinfList(int start) {

return list(start, infList(start+1)); }

doesn’t work. (Why?)A less obvious implementation, usingsuspensions, does work:infList(int start) {

return list(start, function() { return infList(start+1); });}

Now, whenever we are given aninfinite list, we get two things: thefirst integer in the list and asuspension function. When called,this function will give you the rest ofthe infinite list (again, one more

84CS 538 Spring 2003©

value and another suspensionfunction).The whole list is there, but only asmuch as you care to access is actuallycomputed.

Page 22: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

85CS 538 Spring 2003©

Eager Parameter EvaluationSometimes we want parametersevaluated eagerly—as soon as they areknown.Consider a sorting routine that breaksan array in half, sorts each half, andthen merges together the two sortedhalves (this is a merge sort).In outline form it is:sort(inputArray) { ... merge(sort(leftHalf(inputArray),

sort(rightHalf(inputArray));}

This definition lends itself nicely toparallel evaluation: The two halves ofan input array can be sorted inparallel. Each of these two halves canagain be split in two, allowing parallelsorting of four quarter-sized arrays,

86CS 538 Spring 2003©

then leading to 8 sorts of 1/8 sizedarrays, etc.But,to make this all work, the twoparameters to merge must beevaluated eagerly, rather than insequence.

87CS 538 Spring 2003©

Type EquivalenceProgramming languages use types todescribe the values a data object mayhold and the operations that may beperformed.By checking the types of values,potential errors in expressions,assignments and calls may beautomatically detected. For example,type checking tells us that

123 + "123"

is illegal because addition is notdefined for an integer, stringcombination.Type checking is usually done atcompile-time; this is static typing.Type-checking may also be done atrun-time; this is dynamic typing.

88CS 538 Spring 2003©

A program is type-safe if it isimpossible to apply an operation to avalue of the wrong type. In a type-safe language, plus is never told toadd an integer to a string, because itsdefinition does not allow thatcombination of operands. In type-safe programs an operator can stillsee an illegal value (e.g., a division byzero), but it can’t see operands of thewrong type.A strongly-typed programminglanguage forbids the execution oftype-unsafe programs.Weakly-typed programming languagesallow the execution of potentiallytype-unsafe programs.

Page 23: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

89CS 538 Spring 2003©

The question reduces to whether theprogramming language allowsprogrammers to “break” the typerules, either knowingly orunknowingly.Java is strongly typed; type errorspreclude execution. C and C++ areweakly typed; you can break the rulesif you wish. For example: int i; int* p;

p = (int *) i * i;

Now p may be used as an integerpointer though multiplication neednot produce valid integer pointers.

90CS 538 Spring 2003©

If we are going to do type checking ina program, we must decide whethertwo types, T1 and T2 are equivalent;that is, whether they be usedinterchangeably.There are two major approaches totype equivalence:Name Equivalence:Two types are equivalent if and onlyif they refer to exactly the same typedeclaration.For example, type PackerSalaries = int[100];

type AssemblySizes = int[100]; PackerSalaries salary; AssemblySizes size;

91CS 538 Spring 2003©

Issal = size;

allowed?Using name equivalence, no. That is,salary /≡N size since these twovariables have different typedeclarations (that happen to beidentical in structure).Formally, we define ≡N (name typeequivalence) as:(a) T ≡N T

(b) Given the declarationType T1 = T2;

T1 ≡N T2

92CS 538 Spring 2003©

We treat anonymous types (types notgiven a name) as an abbreviation foran implicit declaration of a new andunique type name.Thus int A[10];

is an abbreviation for Type T new = int[10];

T new A;

Page 24: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

93CS 538 Spring 2003©

Structural EquivalenceAn alternative notion of typeequivalence is structural equivalence(denoted ≡S). Roughly, two types arestructurally equivalent if the twotypes have the same definition,independent of where the definitionsare located. That is, the two typeshave the same definitional structure.

94CS 538 Spring 2003©

Formally, (a) T ≡S T

(b) Given the declaration Type T = Q;

T ≡S Q

(c) If T and Q are defined using thesame type constructor andcorresponding parameters in the twodefinitions are equal or structurallyequivalentthen T ≡S Q

95CS 538 Spring 2003©

Returning to our previous example, type PackerSalaries = int[100];

type AssemblySizes = int[100]; PackerSalaries salary; AssemblySizes size;

salary ≡S size since both are arraysand 100=100 and int ≡S int .

96CS 538 Spring 2003©

Which notion of Equivalence doProgramming Languages Use?

C and C++ use structural equivalenceexcept for structs and classes (wherename equivalence is used). For arrays,size is ignored.Java uses structural equivalence forscalars. For arrays, it requires nameequivalence for the component type,ignoring size. For classes it uses nameequivalence except that a subtypemay be used where a parent type isexpected. Thus given void subr(Object O) { ... };

the call subr(new Integer(100));

is OK since Integer is a subclass ofObject .

Page 25: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

97CS 538 Spring 2003©

Automatic Type ConversionsC, C++ and Java also allow variouskinds of automatic type conversions.In C, C++ and Java, a float will beautomatically created from an int : float f = 10; // No type error

Also, an integer type (char , short ,int , long ) will be widened: int i = 'x';

In C and C++ (but not Java), aninteger value can also be narrowed,possibly with the loss of significantbits: char c = 1000000;

98CS 538 Spring 2003©

Reading Assignment• Roosta: Sections 13.1, 13.2

• The Scheme Language Definition (linked from class web page)

99CS 538 Spring 2003©

Lisp & SchemeLisp (List Processing Language) is oneof the oldest programming languagesstill in wide use.It was developed in the late 50s andearly 60s by John McCarthy.Its innovations include:• Support of symbolic computations.

• A functional programming stylewithout emphasis on assignmentsand side-effects.

• A naturally recursive programmingstyle.

• Dynamic (run-time) type checking.

• Dynamic data structures (lists, binarytrees) that grow without limit.

100CS 538 Spring 2003©

• Automatic garbage collection tomanage memory.

• Functions are treated as “first class”values; they may be passed asarguments, returned as result values,stored in data structures, and createdduring execution.

• A formal semantics (written in Lisp)that defines the meaning of all validprograms.

• An Integrated ProgrammingEnvironment to create, edit and testLisp programs.

Page 26: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

101CS 538 Spring 2003©

SchemeScheme is a recent dialect of Lisp.It uses lexical (static) scoping.It supports true first-class functions.It provides program-level access tocontrol flow via continuationfunctions.

102CS 538 Spring 2003©

Atomic (Primitive) Data TypesSymbols:Essentially the same form asidentifiers. Similar to enumerationvalues in C and C++.Very flexible in structure; essentiallyany sequence of printable charactersis allowed; anything that starts avalid number (except + or -) may notstart a symbol.Valid symbols include: abc hello-world + <=!

Integers:Any sequence of digits, optionallyprefixed with a + or -. Usuallyunlimited in length.

103CS 538 Spring 2003©

Reals:A floating point number in a decimalformat (123.456 ) or in exponentialformat (1.23e45 ). A leading sign anda signed exponent are allowed(-12.3 , 10.0e-20 ).Rationals:Rational numbers of the form integer/integer (e.g., 1/3 or 9/7 ) with anoptional leading sign (-1/2 , +7/8 ).Complex:Complex numbers of the formnum+num i or num-num i, wherenum is an integer or real number.Example include 1+3i , -1.5-2.5i ,0+1i ).

104CS 538 Spring 2003©

String:A sequence of characters delimited bydouble quotes. Double quotes andbackslashes must be escaped using abackslash. For example

"Hello World" "\"Wow!\""

Character:A single character prefixed by #\ . Forexample, #\a , #\0 , #\\ , #\# . Twospecial characters are #\space and#\newline .Boolean:True is represented as #t and false isrepresented as #f .

Page 27: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

105CS 538 Spring 2003©

Binary TreesBinary trees are also calledS-Expressions in Lisp and Scheme.They are of the form ( item . item )where item is any atomic value or anyS-Expression. For example:

( A . B ) (1.2 . "xyz" ) ( (A . B ) . C ) ( A . (B . C ) )

S-Expressions are linearizations ofbinary trees:

A B 1.2 "xyz"

106CS 538 Spring 2003©

S-Expressions are built and accessedusing the predefined functions cons,car and cdr.cons builds a new S-Expression fromtwo S-Expressions that represent theleft and right children.cons(E1,E2) = (E1 . E2)car returns are left subtree of anS-Expression.car (E1 . E2) = E1cdr returns are right subtree of anS-Expression.cdr (E1 . E2) = E2

C A

A B B C

107CS 538 Spring 2003©

ListsIn Lisp and Scheme lists are a special,widely-used form of S-Expressions.() represents the empty or null list(A) represents the list containing A.By definition, (A) ≡ (A . () )

(A B) represents the list containing Aand B. By definition,(A B) ≡ (A . (B . () ) )

In general, (A B C ... Z) ≡(A . (B . (C . ... (Z . () ) ... )))

(A B C ) ≡

A

B

C ()

108CS 538 Spring 2003©

Function CallsIn List and Scheme, function calls arerepresented as lists.(A B C) means:Evaluate A (to a function)Evaluate B and C (as parameters)Call A with B and C as its parametersThen use the value returned by thecall as the “meaning” of (A B C) .cons , car and cdr are predefinedsymbols bound to built-in functionsthat build and access lists andS-Expressions.Literals (of type integer, real, rational,complex, string, character andboolean) evaluate to themselves.

Page 28: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

109CS 538 Spring 2003©

For example (⇒ means “evaluatesto”)(cons 1 2) ⇒ (1 . 2)

(cons 1 () ) ⇒ (1)

(car (cons 1 2)) ⇒ 1

(cdr (cons 1 ())) ⇒ ()

But,(car (1 2)) fails during execution!

Why?The expression (1 2) looks like a call,but 1 isn’t a function! We need someway to “quote” symbols and lists wedon’t want evaluated.(quote arg)

is a special function that returns itsargument unevaluated.

110CS 538 Spring 2003©

Thus (quote (1 2)) doesn’t try toevaluate the list (1 2) ; it just returnsit.Since quotation is so often used, itmay be abbreviated using a singlequote. That is(quote arg) ≡ 'arg

Thus(car '(a b c)) ⇒ a

(cdr '( (A) (B) (C))) ⇒( (B) (C) )

(cons 'a '1) ⇒ (a . 1)

But,('cdr '(A B)) fails!

Why?

111CS 538 Spring 2003©

User-defined FunctionsThe list(lambda (args) (body))

evaluates to a function with (args)as its argument list and (body) asthe function body.No quotes are needed for (args) or(body) .Thus(lambda (x) (+ x 1)) evaluates

to the increment function.Similarly,((lambda (x) (+ x 1)) 10) ⇒

11

112CS 538 Spring 2003©

We can bind values and functions toglobal symbols using the definefunction.The general form is(define id object)

id is not evaluated but object is. idis bound to the value object evaluatesto.For example,(define pi 3.1415926535)

(define plus1 (lambda (x) (+ x 1)) )

(define pi*2 (* pi 2))

Once a symbol is defined, it evaluatesto the value it is bound to:(plus1 12) ⇒ 13

Page 29: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

113CS 538 Spring 2003©

Since functions are frequentlydefined, we may abbreviate(define id (lambda (args) (body)) )

as(define (id args) (body) )

Thus(define (plus1 x) (+ x 1))

114CS 538 Spring 2003©

Conditional Expressions inScheme

A predicate is a function that returnsa boolean value. By convention, inScheme, predicate names end with “?”For example, number? symbol? equal? null? list?

In conditionals, #f is false, andeverything else, including #t , is true.The if expression is(if pred E1 E2)

First pred is evaluated. Depending onits value (#f or not), either E1 or E2is evaluated (but not both) andreturned as the value of the ifexpression.

115CS 538 Spring 2003©

For example, (if (= 1 (+ 0 1))

'Yes

'No )

(define (fact n)

(if (= n 0)

1

(* n (fact (- n 1))) ))

116CS 538 Spring 2003©

Generalized ConditionalThis is similar to a switch or case:(cond (p1 e1) (p2 e2) ... (else en))

Each of the predicates (p1 , p2 , ...) isevaluated until one is true (≠ #f ).Then the corresponding expression(e1 , e2 , ...) is evaluated and returnedas the value of the cond . else actslike a predicate that is always true.Example:

(cond

((= a 1) 2) ((= a 2) 3) (else 4) )

Page 30: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

117CS 538 Spring 2003©

Recursion in SchemeRecursion is widely used in Schemeand most other functionalprogramming languages.Rather than using a loop to stepthrough the elements of a list orarray, recursion breaks a problem on alarge data structure into a simplerproblem on a smaller data structure.A good example of this approach isthe append function, which joins (orappends) two lists into one larger listcontaining all the elements of thetwo input lists (in the correct order).Note that cons is not append . consadds one element to the head of anexisting list.

118CS 538 Spring 2003©

Thus(cons '(a b) '(c d)) ⇒ ((a b) c d)

(append '(a b) '(c d)) ⇒ (a b c d)

The append function is predefined inScheme, as are many other usefullist-manipulating functions (consultthe Scheme definition for what’savailable).It is instructive to define appenddirectly to see its recursive approach:(define (append L1 L2) (if (null? L1) L2 (cons (car L1) (append (cdr L1) L2)) ))

119CS 538 Spring 2003©

Let’s trace (append '(a b) '(c d))

Our definition is(define (append L1 L2) (if (null? L1) L2 (cons (car L1) (append (cdr L1) L2)) ))

Now L1 = (a b) and L2 = (c d) .(null? L1) is false, so we evaluate(cons (car L1) (append (cdr L1) L2))= (cons (car '(a b))

(append (cdr '(a b)) '(c d)))= (cons 'a (append '(b) '(c d))

We need to evaluate (append '(b) '(c d))

In this call, L1 = (b) and L2 = (c d) .L1 is not null, so we evaluate(cons (car L1) (append (cdr L1) L2))= (cons (car '(b)) (append (cdr '(b)) '(c d)))

120CS 538 Spring 2003©

= (cons 'b (append '() '(c d))

We need to evaluate (append '() '(c d))

In this call, L1 = () and L2 = (c d) .L1 is null, so we return (c d) .Therefore(cons 'b (append '() '(c d)) =(cons 'b '(c d)) = (b c d) =(append '(b) '(c d))

Finally,(append '(a b) '(c d)) =(cons 'a (append '(b) '(c d)) =

(cons 'a '(b c d)) = (a b c d)

Note:Source files for append , and otherScheme examples, may be found in~cs538-1/public/scheme/example1.scm,~cs538-1/public/scheme/example2.scm,etc.

Page 31: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

121CS 538 Spring 2003©

Reversing a ListAnother useful list-manipulationfunction is rev , which reverses themembers of a list. That is, the lastelement becomes the first element,the next-to-last element becomes thesecond element, etc.For example,(rev '(1 2 3)) ⇒ (3 2 1)

The definition of rev isstraightforward:(define (rev L) (if (null? L) L (append (rev (cdr L)) (list (car L)) ) ))

122CS 538 Spring 2003©

As an example, consider(rev '(1 2))

Here L = (1 2) . L is not null so weevaluate(append (rev (cdr L)) (list (car L))) =(append (rev (cdr '(1 2))) (list (car '(1 2)))) =

(append (rev '(2)) (list 1)) =(append (rev '(2)) '(1))

We must evaluate (rev '(2))

Here L = (2) . L is not null so weevaluate(append (rev (cdr L)) (list (car L))) =

(append (rev (cdr '(2))) (list (car '(2)))) =(append (rev ())(list 2)) =(append (rev ())'(2))

We must evaluate (rev '())

Here L = () . L is null so (rev '())=()

123CS 538 Spring 2003©

Thus (append (rev ())'(2)) =(append () '(2)) = (2) = (rev '(2))

Finally, recall (rev '(1 2)) =(append (rev '(2)) '(1)) =(append '(2) '(1)) = (2 1)

As constructed, rev only reverses the“top level” elements of a list. That is,members of a list that themselves arelists aren’t reversed.For example, (rev '( (1 2) (3 4))) = ((3 4) (1 2))

We can generalize rev to also reverselist members that happen to be lists.To do this, it will be convenient to useScheme’s let construct.

124CS 538 Spring 2003©

The Let ConstructScheme allows us to create localnames, bound to values, for use in anexpression.The structure is(let ( (id1 val1) (id2 val2) ... ) expr )

In this construct, val1 is evaluatedand bound to id1 , which will existonly within this let expression. Ifid1 is already defined (as a global orparameter name) the existingdefinition is hidden and the localdefinition, bound to val1 , is used.Then val2 is evaluated and bound toid2 , .... Finally, expr is evaluated in ascope that includes id1 , id2 , ...

Page 32: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

125CS 538 Spring 2003©

For example,(let ( (a 10) (b 20) )

(+ a b)) ⇒ 30

Using a let , the definition ofrevall , a version of rev thatreverses all levels of a list, is easy:

(define (revall L)

(if (null? L) L (let ((E (if (list? (car L)) (revall (car L)) (car L) ))) (append (revall (cdr L)) (list E)) ) ))

(revall '( (1 2) (3 4))) ⇒ ((4 3) (2 1))

126CS 538 Spring 2003©

SubsetsAnother good example of Scheme’srecursive style of programming issubset computation.Given a list of distinct atoms, wewant to compute a list of all subsetsof the list values.For example,(subsets '(1 2 3)) ⇒

( () (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))

The order of atoms and sublists isunimportant, but all possible subsetsof the list values must be included.Given Scheme’s recursive style ofprogramming, we need a recursivedefinition of subsets.

127CS 538 Spring 2003©

That is, if we have a list of all subsetsof n atoms, how do we extend thislist to one containing all subsets ofn+1 values?First, we note that the number ofsubsets of n+1 values is exactly twicethe number of subsets of n values.For example,(subsets '(1 2) ) ⇒( () (1) (2) (1 2)) , which

contains 4 subsets.(subsets '(1 2 3)) contains 8subsets (as we saw earlier).Moreover, the extended list (ofsubsets for n+1 values) is simply thelist of subsets for n values plus theresult of “distributing” the new valueinto each of the original subsets.

128CS 538 Spring 2003©

Thus (subsets '(1 2 3)) ⇒( () (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)) =( () (1) (2) (1 2) ) plus

( (3) (1 3) (2 3) (1 2 3) )

This insight leads to a conciseprogram for subsets.We will let (distrib L E) be afunction that “distributes” E intoeach list in L.For example,(distrib ' (() (1) (2) (1 2)) 3) =

( (3) (3 1) (3 2) (3 1 2) )

(define (distrib L E) (if (null? L) () (cons (cons E (car L)) (distrib (cdr L) E)) ))

Page 33: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

129CS 538 Spring 2003©

We will let (extend L E) extend alist L by distributing element Ethrough L and then appending thisresult to L.For example,(extend '( () (a) ) 'b) ⇒

( () (a) (b) (b a))

(define (extend L E) (append L (distrib L E)))

Now subsets is easy:

(define (subsets L)

(if (null? L) (list ()) (extend (subsets (cdr L))

(car L)) ))

130CS 538 Spring 2003©

Data Structures in SchemeIn Scheme, lists and S-expressions arebasic. Arrays can be simulated usinglists, but access to elements “deep” inthe list can be slow (since a list is alinked structure).To access an element deep within alist we can use:• (list-tail L k)

This returns list L after removing thefirst k elements. For example,(list-tail '(1 2 3 4 5) 2) ⇒(3 4 5)

• (list-ref L k)

This returns the k-th element in L(counting from 0). For example,(list-ref '(1 2 3 4 5) 2) ⇒ 3

131CS 538 Spring 2003©

Vectors in SchemeScheme provides a vector type thatdirectly implements one dimensionalarrays.Literals are of the form #( ... )

For example, #(1 2 3) or#(1 2.0 "three")

The function (vector? val) testswhether val is a vector or not.(vector? 'abc) ⇒ #f

(vector? '(a b c)) ⇒ #f

(vector? #(a b c)) ⇒ #t

The function (vector v1 v2 ...)evaluates v1 , v2 , ... and puts theminto a vector.(vector 1 2 3) ⇒ #(1 2 3)

132CS 538 Spring 2003©

The function (make-vector k val)creates a vector composed of k copiesof val . Thus(make-vector 4 (/ 1 2)) ⇒ #(1/2 1/2 1/2 1/2)

The function (vector-ref vect k)returns the k-th element of vect ,starting at position 0. It is essentiallythe same as vect[k] in C or Java. Forexample,(vector-ref #(2 4 6 8 10) 3) ⇒

8

The function(vector-set! vect k val) setsthe k-th element of vect , starting atposition 0, to be val . It is essentiallythe same as vect[k]=val in C orJava. The value returned by thefunction is unspecified. The suffix “!”in set! indicates that the function

Page 34: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

133CS 538 Spring 2003©

has a side-effect. For example,(define v #(1 2 3 4 5))(vector-set! v 2 0)v ⇒ #(1 2 0 4 5)

Vectors aren’t lists (and lists aren’tvectors).Thus (car #(1 2 3)) doesn’t work.There are conversion routines:• (vector->list V) converts vector

V to a list containing the same valuesas V. For example,(vector->list #(1 2 3)) ⇒ (1 2 3)

• (list->vector L) converts list Lto a vector containing the samevalues as L. For example,(list->vector '(1 2 3)) ⇒#(1 2 3)

134CS 538 Spring 2003©

• In general Scheme names aconversion function from type T totype Q as T->Q . For example,string->list converts a stringinto a list containing the charactersin the string.

135CS 538 Spring 2003©

Records and StructsIn Scheme we can represent a record,struct, or class object as anassociation list of the form((obj1 val1) (obj2 val2) ...)

In the association list, which is a listof (object value) sublists, objectserves as a “key” to locate the desiredsublist.For example, the association list( (A 10) (B 20) (C 30) )

serves the same role asstruct

{ int a = 10; int b = 20; int c = 30;}

136CS 538 Spring 2003©

The predefined Scheme function(assoc obj alist)

checks alist (an association list) tosee if it contains a sublist with obj asits head. If it does, the list startingwith obj is returned; otherwise #f(indicating failure) is returned.For example,(define L '( (a 10) (b 20) (c 30) ) )

(assoc 'a L) ⇒ (a 10)

(assoc 'b L) ⇒ (b 20)

(assoc 'x L) ⇒ #f

Page 35: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

137CS 538 Spring 2003©

We can use non-atomic objects askeys too!(define price-list

'( ((bmw m5) 71095)

((bmw z4) 40495)

((jag xj8) 56975)

((mb sl500) 86655)

)

)

(assoc '(bmw z4) price-list)⇒ ((bmw z4) 40495)

138CS 538 Spring 2003©

Using assoc , we can easily define astructure function:(structure key alist) will returnthe value associated with key inalist ; in C or Java notation, itreturns alist.key .(define (structure key alist) (if (assoc key alist)

(car (cdr (assoc key alist))) #f ))

We can improve this function in twoways:• The same call to assoc is made

twice; we can save the valuecomputed by using a let expression.

• Often combinations of car and cdrare needed to extract a value. Scheme

139CS 538 Spring 2003©

has a number of predefined functionsthat combine several calls to car andcdr into one function. For example,(caar x) ≡ (car (car x))

(cadr x) ≡ (car (cdr x))

(cdar x) ≡ (cdr (car x))

(cddr x) ≡ (cdr (cdr x))

Using these two insights we can nowdefine a better version of structure

(define (structure key alist) (let ((p (assoc key alist))) (if p (cadr p) #f ) ) )

140CS 538 Spring 2003©

What does assoc do if more than onesublist with the same key exists?It returns the first sublist with amatching key. In fact, this propertycan be used to make a simple and fastfunction that updates associationlists:(define (set-structure key alist val) (cons (list key val) alist))

Page 36: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

141CS 538 Spring 2003©

If we want to be more space-efficient, we can create a version thatupdates the internal structure of anassociation list, using set-cdr!which changes the cdr value of a list:(define (set-structure! key alist val) (let ( (p (assoc key alist))) (if p (begin (set-cdr! p (list val)) alist ) (cons (list key val) alist) ) ))

142CS 538 Spring 2003©

Functions are First-classObjects

Functions may be passed asparameters, returned as the value of afunction call, stored in data objects,etc.This is a consequence of the fact that(lambda (args) (body))

evaluates to a function just as(+ 1 1)

evaluates to an integer.

143CS 538 Spring 2003©

ScopingIn Scheme scoping is static (lexical).This means that non-local identifiersare bound to containing lambdaparameters, or let values, or globallydefined values. For example,(define (f x) (lambda (y) (+ x y)))

Function f takes one parameter, x . Itreturns a function (of y ), with x inthe returned function bound to thevalue of x used when f was called.Thus

(f 10) ≡ (lambda (y) (+ 10 y))

((f 10) 12) ⇒ 22

144CS 538 Spring 2003©

Unbound symbols are assumed to beglobals; there is a run-time error if anunbound global is referenced. Forexample,(define (p y) (+ x y))

(p 20) ; error -- x is unbound

(define x 10)

(p 20) ⇒ 30

We can use let bindings to createprivate local variables for functions:(define F (let ( (X 1) ) (lambda () X) ))

F is a function (of no arguments).(F) calls F.(define X 22)

(F) ⇒ 1;X used in F is private

Page 37: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

145CS 538 Spring 2003©

We can encapsulate internal statewith a function by using private, let-bound variables:(define cnt (let ( (I 0) ) (lambda ()

(set! I (+ I 1)) I) ))

Now, (cnt) ⇒ 1

(cnt) ⇒ 2

(cnt) ⇒ 3

etc.

146CS 538 Spring 2003©

Let Bindings can be SubtleYou must check to see if the let-bound value is created when thefunction is created or when it iscalled.Compare(define cnt

(let ( (I 0) ) (lambda ()

(set! I (+ I 1)) I) ) )vs. (define reset (lambda () (let ( (I 0) )

(set! I (+ I 1)) I) ) )(reset) ⇒ 1, (reset) ⇒ 1, etc.

147CS 538 Spring 2003©

Simulating Class ObjectsUsing association lists and privatebound values, we can encapsulatedata and functions. This gives us theeffect of class objects.(define (point x y) (list (list 'rect (lambda () (list x y))) (list 'polar (lambda () (list (sqrt (+ (* x x) (* y y))) (atan (/ x y)) ) ) ) ))

A call (point 1 1) creates anassociation list of the form( (rect funct) (polar funct) )

148CS 538 Spring 2003©

We can use structure to accesscomponents:(define p (point 1 1) )

( (structure 'rect p) ) ⇒ (1 1)

( (structure 'polar p) ) ⇒

( )2π4---

Page 38: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

149CS 538 Spring 2003©

We can add new functionality by justadding new (id function) pairs tothe association list.(define (point x y) (list (list 'rect (lambda () (list x y))) (list 'polar (lambda () (list (sqrt (+ (* x x) (* y y))) (atan (/ x y)) ))) (list 'set-rect! (lambda (newx newy) (set! x newx) (set! y newy) (list x y) )) (list 'set-polar! (lambda (r theta) (set! x (* r (sin theta))) (set! y (* r (cos theta))) (list r theta) ))))

150CS 538 Spring 2003©

Now we have(define p (point 1 1) )

( (structure 'rect p) ) ⇒ (1 1)

( (structure 'polar p) ) ⇒

( )

((structure 'set-polar! p) 1 π/4)⇒ (1 π/4)

( (structure 'rect p) ) ⇒

( )

2π4---

1

2------- 1

2-------

151CS 538 Spring 2003©

Limiting Access to InternalStructure

We can improve upon our associationlist approach by returning a singlefunction (similar to a C++ or Javaobject) rather than an explicit list of(id function) pairs.The function will take the name ofthe desired operation as one of itsarguments.

152CS 538 Spring 2003©

First, let’s differentiate between(define def1 (let ( (I 0) ) (lambda () (set! I (+ I 1)) I) ))

and(define (def2) (let ( (I 0) ) (lambda () (set! I (+ I 1)) I) ))

def1 is a function of zero argumentsthat increments a local variable andreturns its updated value.def2 is a function (of zeroarguments) that generates a functionof zero arguments (that increments alocal variable and returns its updatedvalue). Each call to def2 creates adifferent function.

Page 39: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

153CS 538 Spring 2003©

Stack Implemented as aFunction

(define ( stack ) (let ( (s () ) ) (lambda (op . args) ; var # args (cond ((equal? op 'push!)

(set! s (cons (car args) s)) (car s)) ((equal? op 'pop!) (if (null? s) #f (let ( (top (car s)) ) (set! s (cdr s)) top ))) ((equal? op 'empty?) (null? s)) (else #f) ) ) ))

154CS 538 Spring 2003©

(define stk (stack)) ;new empty stack

(stk 'push! 1) ⇒ 1 ;s = (1)

(stk 'push! 3) ⇒ 3 ;s = (3 1)

(stk 'push! 'x) ⇒ x ;s = (x 3 1)

(stk 'pop!) ⇒ x ;s = (3 1)

(stk 'empty?) ⇒ #f ;s = (3 1)

(stk 'dump) ⇒ #f ;s = (3 1)

155CS 538 Spring 2003©

Higher-Order FunctionsA higher-order function is a functionthat takes a function as a parameteror one that returns a function as itsresult.A very important (and useful) higher-order function is map, which applies afunction to a list of values andproduces a list or results:(define (map f L) (if (null? L) () (cons (f (car L)) (map f (cdr L))) ))

Note: In Scheme’s built-inimplementation of map, the order offunction application is unspecified.

156CS 538 Spring 2003©

(map sqrt '(1 2 3 4 5)) ⇒ (1 1.414 1.732 2 2.236)

(map (lambda(x) (* x x)) '(1 2 3 4 5)) ⇒ (1 4 9 16 25)

Map may also be used with multipleargument functions by supplyingmore than one list of arguments:(map + '(1 2 3) '(4 5 6)) ⇒ (5 7 9)

Page 40: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

157CS 538 Spring 2003©

The Reduce FunctionAnother useful higher-order functionis reduce , which reduces a list ofvalues to a single value by repeatedlyapplying a binary function to the listvalues.This function takes a binary function,a list of data values, and an identityvalue for the binary function:(define (reduce f L id) (if (null? L) id (f (car L) (reduce f (cdr L) id)) ))

(reduce + '(1 2 3 4 5) 0) ⇒15

(reduce * '(1 2 4 6 8 10) 1)⇒ 3840

158CS 538 Spring 2003©

(reduce append '((1 2 3) (4 5 6) (7 8)) ())⇒ (1 2 3 4 5 6 7 8)

(reduce expt '(2 2 2 2) 1) ⇒

= 65536

(reduce expt '(2 2 2 2 2) 1)⇒ 2 65536

(string-length (number->string

(reduce expt '( 2 2 2 2 2) 1)))⇒ 19729 ; digits in 2 65536

2222

159CS 538 Spring 2003©

Sharing vs. CopyingIn languages without side-effects anobject can be copied by copying apointer (reference) to the object; acomplete new copy of the object isn’tneeded.Hence in Scheme (define A B)normally means

But, if side-effects are possible wemay need to force a physical copy ofan object or structure:

A B

160CS 538 Spring 2003©

(define (copy obj)

(if (pair? obj)

(cons (copy (car obj))(copy (cdr obj)))

obj

))

For example,(define A '(1 2))

(define B (cons A A))

B = ( (1 2) 1 2)

A B

1

2 ()

Page 41: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

161CS 538 Spring 2003©

(set-car! (car B) 10)

B = ( (10 2) 10 2)

(define C (cons (copy A) (copy A)))

A B

10

2 ()

C

10

2 ()

10

2 ()

162CS 538 Spring 2003©

(set-car! (car C) 20)

C = ((20 2) 10 2)

Similar concerns apply to strings andvectors, because their internalstructure can be changed.

C

20

2 ()

10

2 ()

163CS 538 Spring 2003©

Shallow & Deep CopyingA copy operation that copies apointer (or reference) rather than theobject itself is a shallow copy.For example, In Java,Object O1 = new Object();

Object O2 = new Object();

O1 = O2; // shallow copy

If the structure within an object isphysically copied, the operation is adeep copy.In Java, for objects that support theclone operation,O1 = O2.clone(); // deep copy

Even in Java’s deep copy (via theclone() operation), objectsreferenced from within an object areshallow copied. Thus given

164CS 538 Spring 2003©

class List {

int value;

List next;

}

List L,M;

M = L.clone();

L.value and M.value areindependent, but L.next and M.nextrefer to the same List object.A complete deep copy, that copies allobjects linked directly or indirectly, isexpensive and tricky to implement.(Consider a complete copy of acircular linked list).

Page 42: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

165CS 538 Spring 2003©

Equality Checking in SchemeIn Scheme = is used to test fornumeric equality (includingcomparison of different numerictypes). Non-numeric arguments causea run-time error. Thus(= 1 1) ⇒ #t

(= 1 1.0) ⇒ #t

(= 1 2/2) ⇒ #t

(= 1 1+0.0i) ⇒ #t

166CS 538 Spring 2003©

To compare non-numeric values, wecan use either:pointer equivalence (do the twooperands point to the same address inmemory)structural equivalence (do the twooperands point to structures with thesame size, shape and components,even if they are in different memorylocations)In general pointer equivalence isfaster but less accurate.

167CS 538 Spring 2003©

Scheme implements both kinds ofequivalence tests.(eqv? obj1 obj2)

This tests if obj1 and obj2 are theexact same object. This works foratoms and pointers to the samestructure.(equal? obj1 obj2)

This tests if obj1 and obj2 are thesame, component by component. Thisworks for atoms, lists, vectors andstrings.

(eqv? 1 1) ⇒ #t

(eqv? 1 (+ 0 1)) ⇒ #t

(eqv? 1/2 (- 1 1/2)) ⇒ #t

(eqv? (cons 1 2) (cons 1 2)) ⇒#f

(eqv? "abc" "abc") ⇒ #f

168CS 538 Spring 2003©

(equal? 1 1) ⇒ #t

(equal? 1 (+ 0 1)) ⇒ #t

(equal? 1/2 (- 1 1/2)) ⇒ #t

(equal? (cons 1 2) (cons 1 2)) ⇒#t

(equal? "abc" "abc") ⇒ #t

In general it is wise to use equal?unless speed is a critical factor.

Page 43: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

169CS 538 Spring 2003©

I/O in SchemeScheme provides simple read andwrite functions, directed to the“standard in” and “standard out” files.(read)

Reads a single Scheme object (anatom, string, vector or list) from thestandard in file. No quoting is needed.(write obj)

Writes a single object, obj , to thestandard out file.(display obj)

Writes obj to the standard out file ina more readable format. (Stringsaren’t quoted, and characters aren’tescaped.)(newline)

Forces a new line on standard out file.

170CS 538 Spring 2003©

PortsPorts are Scheme objects thatinterface with systems files. I/O tofiles is normally done through a portobject bound to a system file.(open-input-file "path to file")

This returns an input port associatedwith the "path to file" string(which is system dependent). A run-time error is signalled if "path tofile" specifies an illegal orinaccessible file.(read port)

Reads a single Scheme object (anatom, string, vector or list) fromport , which must be an input portobject.

171CS 538 Spring 2003©

(eof-object? obj)

When the end of an input file isreached, a special eof-object isreturned. eof-object? tests whetheran object is this special end-of-filemarker.(open-output-file "path to file")

This returns an output port associatedwith the "path to file" string(which is system dependent). A run-time error is signalled if "path tofile" specifies an illegal orinaccessible file.(write obj port)

Writes a single object, obj , to theoutput port specified by port .

172CS 538 Spring 2003©

(display obj port)

Writes obj to the output portspecified by port . display uses a morereadable format than write does.(Strings aren’t quoted, and charactersaren’t escaped.)(close-input-port port)

This closes the input port specified byport .(close-output-port port)

This closes the output port specifiedby port .

Page 44: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

173CS 538 Spring 2003©

Example—Reading & Echoing aFile

We will iterate through a file, readingand echoing its contents. We need agood way to do iteration; recursion isneither natural nor efficient here.Scheme provides a nice generalizationof the let expression that is similarto C’s for loop.(let X ( (id1 val1) (id2 val2) ... ) ... (X v1 v2 ...))

A name for the let (X in the example)is provided. As usual, val1 isevaluated and bound to id1 , val2 isevaluated and bound to id2 , etc. Inthe body of the let, the let may be“called” (using its name) with a fresh

174CS 538 Spring 2003©

set of values for the let variables.Thus (X v1 v2 ...) starts the nextiteration of the let with id1 bound tov1 , id2 , bound to v2 , etc.The calls look like recursion, but theyare implemented as loop iterations.For example, in(let loop ( (x 1) (sum 0) )

(if (<= x 10)

(loop (+ x 1) (+ sum x))

sum

)

)

we sum the values of x from 1 to 10.Compare it tofor (x=1,sum=0; x <= 10; sum+=x,x+=1)

{}

175CS 538 Spring 2003©

Now a function to read and echo afile is straightforward:(define (echo filename) (let (

(p (open-input-file filename))) (let loop ( (obj (read p))) (if (eof-object? obj) #t ;normal termination (begin (write obj) (newline) (loop (read p)) ) ) ) ))

176CS 538 Spring 2003©

We can create an alternative to echothat uses(call-with-input-file filename function)

This function opens filename ,creates an input port from it, andthen calls function with that port asan argument:(define (echo2 filename) (call-with-input-file filename (lambda(port)

(let loop ( (obj (read port))) (if (eof-object? obj) #t (begin (write obj) (newline) (loop (read port)) ) ) ) )) )

Page 45: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

177CS 538 Spring 2003©

Control Flow in SchemeNormally, Scheme’s control flow issimple and recursive:• The first argument is evaluated to get

a function.

• Remaining arguments are evaluatedto get actual parameters.

• Actual parameters are bound to thefunction’s formal parameters.

• The functions’ body is evaluated toobtain the value of the function call.

This approach routinely leads todeeply nested expression evaluation.

178CS 538 Spring 2003©

As an example, consider a simplefunction that multiplies a list ofintegers:(define (*list L) (if (null? L) 1 (* (car L)(*list (cdr L))) ))

The call (*list '(1 2 3 4 5))

expands to(* 1 (* 2 (* 3 (* 4 (* 5 1)))))

But,what if we get clever and decide toimprove this function by noting thatif 0 appears anywhere in list L, theproduct must be 0?

179CS 538 Spring 2003©

Let’s try(define (*list0 L) (cond ((null? L) 1) ((= 0 (car L)) 0) (else (* (car L) (*list0 (cdr L)))) ))

This helps a bit—we never go past azero in L, but we still unnecessarily doa sequence of pending multiplies, allof which must yield zero!Can we escape from a sequence ofnested calls once we know they’reunnecessary?

180CS 538 Spring 2003©

ExceptionsIn languages like Java, a statementmay throw an exception that’s caughtby an enclosing exception handler.Code between the statement thatthrows the exception and the handlerthat catches it is abandoned.Let’s solve the problem of avoidingmultiplication of zero in Java, usingits exception mechanism:class Node {

int val;

Node next;

}

class Zero extends Throwable{};

Page 46: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

181CS 538 Spring 2003©

int mult (Node L) {

try {

return multNode(L);

} catch (Zero z) {

return 0;

}

}

int multNode(Node L)

throws Zero {

if (L == null)

return 1;

else if (L.val == 0)

throw new Zero();

else return L.val * multNode(L.next);

}

In this implementation, no multipliesby zero are ever done.

182CS 538 Spring 2003©

ContinuationsIn our Scheme implementation of*list , we’d like a way to delay doingany multiplies until we know no zerosappear in the list. One approach is tobuild a continuation—a function thatrepresents the context in which afunction’s return value will be used:(define (*listC L con)

(cond ((null? L) (con 1)) ((= 0 (car L)) 0) (else (*listC (cdr L) (lambda (n) (* n (con (car L))))) ) ))

183CS 538 Spring 2003©

The top-level call is(*listC L (lambda (x) x))

For ordinary lists *listC expands to aseries of multiplies, just like *listdid.(define (id x) x)

(*listC '(1 2 3) id) ⇒(*listC '(2 3) (lambda (n) (* n (id 1) ))) ≡(*listC '(2 3) (lambda (n) (* n 1))) ⇒(*listC '(3) (lambda (n) (* n (* 2 1) ))) ≡(*listC '(3) (lambda (n) (* n 2))) ⇒(*listC () (lambda (n) (* n (* 3 2) ))) ≡(*listC () (lambda (n) (* n 6)))

⇒ (* 1 6) ⇒ 6

184CS 538 Spring 2003©

But for a list with a zero in it, we geta different execution path:(*listC '(1 0 3) id) ⇒(*listC '(0 3)

(lambda (n) (* n (id 1) ))) ⇒ 0

No multiplies are done!

Page 47: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

185CS 538 Spring 2003©

Another Example ofContinuations

Let’s redo our list multiply example sothat if a zero is seen in the list wereturn a function that computes theproduct of all the non-zero valuesand a parameter that is the“replacement value” for the unwantedzero value. The function gives thecaller a chance to correct a probableerror in the input data.We create(*list2 L) ≡Product of all integers in L

if no zero appears

else(lambda (n) (* n product-of-all-nonzeros-in-L)

186CS 538 Spring 2003©

(define (*list2 L) (*listE L id))

(define (*listE L con) (cond ((null? L) (con 1)) ((= 0 (car L)) (lambda(n) (* (con n) (*listE (cdr L) id)))) (else (*listE (cdr L) (lambda(m) (* m (con (car L)))))) ))

187CS 538 Spring 2003©

In the following, we check to see if*list2 returns a number or afunction. If a function is returned, wecall it with 1, effectively removing 0from the list(let ( (V (*list2 L)) )

(if (number? V)

V

(V 1)

)

)

188CS 538 Spring 2003©

For ordinary lists *list2 expands toa series of multiplies, just like *listdid.(*listE '(1 2 3) id) ⇒(*listE '(2 3) (lambda (m) (* m (id 1) ))) ≡(*listE '(2 3) (lambda (m) (* m 1))) ⇒(*listE '(3) (lambda (m) (* m (* 2 1) ))) ≡(*listE '(3) (lambda (m) (* m 2))) ⇒(*listE () (lambda (m) (* m (* 3 2) ))) ≡(*listE () (lambda (n) (* n 6)))

⇒ (* 1 6) ⇒ 6

Page 48: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

189CS 538 Spring 2003©

But for a list with a zero in it, we geta different execution path:(*listE '(1 0 3) id) ⇒(*listE '(0 3) (lambda (m) (* m (id 1) ))) ⇒(lambda (n) (* (con n) (* listE '(3) id))) ≡(lambda (n) (* (* n 1)

(* listE '(3) id) )) ≡(lambda (n) (* (* n 1) 3))

This function multiplies n, thereplacement value for 0, by 1 and 3,the non-zero values in the input list.

190CS 538 Spring 2003©

But note that only one zero value inthe list is handled correctly!Why?(define (*listE L con) (cond ((null? L) (con 1)) ((= 0 (car L)) (lambda(n) (* (con n)

(*listE (cdr L) id) ))) (else (*listE (cdr L) (lambda(m) (* m (con (car L)))))) ))

191CS 538 Spring 2003©

Continuations in SchemeScheme provides a built-inmechanism for creatingcontinuations. It has a long name:call-with-current-continuation

This name is usually abbreviated ascall/cc

(perhaps using define ).call/cc takes a single function as itsargument. That function also takes asingle argument. That is, we usecall/cc as(call/cc funct) wherefunct ≡ (lambda (con) (body))

call/cc calls the function that it isgiven with the “current continuation”as the function’s argument.

192CS 538 Spring 2003©

Current ContinuationsWhat is the current continuation?It is itself a function of oneargument. The current continuationfunction represents the executioncontext within which the call/ccappears. The argument to thecontinuation is a value to besubstituted as the return value ofcall/cc in that execution context.For example, given(+ (fct n) 3)

the current continuation for (fct n)is (lambda (x) (+ x 3)

Given (* 2 (+ (fct z) 10))

the current continuation for (fct z)is (lambda (m) (* 2 (+ m 10))

Page 49: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

193CS 538 Spring 2003©

To use call/cc to grab acontinuation in (say) (+ (fct n) 3)we make (fct n) the body of afunction of one argument. Let’s callthat argument return . We thereforecreate(lambda (return) (fct n))

Then(call/cc (lambda (return) (fct n)))

binds the current continuation toreturn and executes (fct n) .We can ignore the currentcontinuation bound to return anddo a normal returnorwe can use return to force a returnto the calling context of thecall/cc .

194CS 538 Spring 2003©

The call (return value) forcesvalue to be returned as the value ofcall/cc in its context of call.Example:

(define (g con) (con 5))

Now during evaluation no divide byzero error occurs. Rather, when(g return) is called, 5 is passed tocon , which is bound to return .Therefore 5 is used as the value of thecall to call/cc , and 50 is computed.

(* (call/cc (lambda(return) (/ (g return) 0))) 10)

return

195CS 538 Spring 2003©

Continuations are JustFunctions

Continuations may be saved invariables or data structures and calledin the future to “reactive” acompleted or suspended computation.(define CC ())(define (F) (let ( (v (call/cc (lambda(here) (set! CC here) 1))))

(display "The ans is: ") (display v)

(newline)) )

This displays The ans is: 1

At any time in the future, (CC 10)will display The ans is: 10

196CS 538 Spring 2003©

List Multiplication RevisitedWe can use call/cc to reimplementthe original *list to force animmediate return of 0 (much like athrow in Java):(define (*listc L return) (cond ((null? L) 1) ((= 0 (car L)) (return 0)) (else (* (car L)

(*listc (cdr L) return)))) )

(define (*list L) (call/cc (lambda (return) (*listc L return)) ))

A 0 in L forces a call of (return 0)which makes 0 the value of call/cc .

Page 50: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

197CS 538 Spring 2003©

Interactive Replacement ofError Values

Using continuations, we can also redo*listE so that zeroes can be replacedinteractively! Multiple zeroes (in bothoriginal and replacement values) arecorrectly handled.(define (*list L) (let ( (V (call/cc (lambda (here) (*liste L here)))) ) (if (number? V) V (begin (display "Enter new value for 0") (newline) (newline) (V (read)) ) ) ))

198CS 538 Spring 2003©

(define (*liste L return) (if (null? L) 1 (let loop ((value (car L))) (if (= 0 value) (loop (call/cc

(lambda (x) (return x)))) (* value (*liste (cdr L) return)) ) ) ))

If a zero is seen, *liste passes backto the caller (via return ) acontinuation that will set the nextvalue of value . This value is checked,so if it is itself zero, a substitute isrequested. Each occurrence of zeroforces a return to the caller for asubstitute value.

199CS 538 Spring 2003©

Implementing Coroutines withcall/cc

Coroutines are a very handygeneralization of subroutines. Acoroutine may suspend its executionand later resume from the point ofsuspension. Unlike subroutines,coroutines do no have to completetheir execution before they return.Coroutines are useful forcomputation of long or infinitestreams of data, where we wish tocompute some data, use it, computeadditional data, use it, etc.Subroutines aren’t always able tohandle this, as we may need to save alot of internal state to resume withthe correct next value.

200CS 538 Spring 2003©

Producer/Consumer usingCoroutines

The example we will use is one of aconsumer of a potentially infinitestream of data. The next integer inthe stream (represented as anunbounded list) is read. Call thisvalue n. Then the next n integers areread and summed together. Theanswer is printed, and the user isasked whether another sum isrequired. Since we don’t know inadvance how many integers will beneeded, we’ll use a coroutine toproduce the data list in segments,requesting another segment asnecessary.

Page 51: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

201CS 538 Spring 2003©

(define (consumer)

(next 0) ; reset next function (let loop ((data (moredata))) (let ( (sum+restoflist (sum-n-elems (car data) (cons 0 (cdr data))))) (display (car sum+restoflist)) (newline) (display "more? ") (if (equal? (read) ’y) (if (= 1

(length sum+restoflist)) (loop (moredata))

(loop (cdr sum+restoflist)) )

#t ; Normal completion ) ) ))

202CS 538 Spring 2003©

Next, we’ll consider sum-n-elems ,which adds the first element of list (arunning sum) to the next n elementson the list. We’ll use moredata toextend the data list as needed.(define (sum-n-elems n list) (cond ((= 0 n) list) ((null? (cdr list)) (sum-n-elems n

(cons (car list)(moredata)))) (else (sum-n-elems (- n 1) (cons (+ (car list) (cadr list)) (cddr list))))

))

203CS 538 Spring 2003©

The function moredata is calledwhenever we need more data. Initiallya producer function is called to getthe initial segment of data. produceractually returns the next datasegment plus a continuation (storedin producer-cc ) used to resumeexecution of producer when thenext data segment is required.

204CS 538 Spring 2003©

(define moredata (let ( (producer-cc () ) ) (lambda () (let ( (data+cont (if (null? producer-cc) (call/cc (lambda (here)

(producer here))) (call/cc (lambda (here) (producer-cc here))) ) )) (set! producer-cc (cdr data+cont)) (car data+cont) ) ) ))

Page 52: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

205CS 538 Spring 2003©

Function (next z) returns the next zintegers in an infinite sequence thatstarts at 1. A value z=0 is a specialflag indicating that the sequenceshould be reset to start at 1.(define next (let ( (i 1)) (lambda (z) (if (= 0 z) (set! i 1) (let loop

((cnt z) (val i) (ints () )) (if (> cnt 0) (loop (- cnt 1) (+ val 1) (append ints (list val))) (begin (set! i val) ints ) ) )) ) ) )

206CS 538 Spring 2003©

The function producer generates aninfinite sequence of integers(1,2,3,...). It suspends every 5/10/15/25 elements and returns control tomoredata .(define (producer initial-return) (let loop ( (return initial-return) ) (set! return (call/cc (lambda (here)

(return (cons (next 5) here))))) (set! return (call/cc (lambda (here)

(return (cons (next 10) here))))) (set! return (call/cc (lambda (here) (return (cons (next 15) here))))) (loop (call/cc (lambda (here)

(return (cons (next 25) here)))))) )

207CS 538 Spring 2003©

Reading Assignment• MULTILISP: a language for concurrent

symbolic computation,by Robert H. Halstead(linked from class web page)

208CS 538 Spring 2003©

Lazy EvaluationLazy evaluation is sometimes called“call by need.” We do an evaluationwhen a value is used; not when it isdefined.Scheme provides for lazy evaluation:(delay expression)

Evaluation of expression is delayed.The call returns a “promise” that isessentially a lambda expression.(force promise)

A promise, created by a call to delay ,is evaluated. If the promise hasalready been evaluated, the valuecomputed by the first call to force isreused.

Page 53: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

209CS 538 Spring 2003©

Example:Though and is predefined, writing acorrect implementation for it is a bittricky.The obvious program(define (and A B)

(if A

B

#f

)

)

is incorrect since B is alwaysevaluated whether it is needed or not.In a call like(and (not (= i 0)) (> (/ j i) 10))

unnecessary evaluation might befatal.

210CS 538 Spring 2003©

An argument to a function is strict ifit is always used. Non-strictarguments may cause failure ifevaluated unnecessarily.With lazy evaluation, we can define amore robust and function:(define (and A B)

(if A

(force B)

#f

)

)

This is called as:(and (not (= i 0)) (delay (> (/ j i) 10)))

Note that making the programmerremember to add a call to delay isunappealing.

211CS 538 Spring 2003©

Delayed evaluation also allows us aneat implementation of suspensions.The following definition of an infinitelist of integers clearly fails(define (inflist i)

(cons i (inflist (+ i 1))))

But with use of delays we get thedesired effect in finite time:(define (inflist i) (cons i (delay (inflist (+ i 1)))))

Now a call like (inflist 1) creates

1 promise for(inflist 2)

212CS 538 Spring 2003©

We need to slightly modify how weexplore suspended infinite lists. Wecan’t redefine car and cdr as theseare far too fundamental to tamperwith.Instead we’ll define head and tail todo much the same job:(define head car)

(define (tail L)

(force (cdr L)))

head looks at car values which arefully evaluated.tail forces one level of evaluation ofa delayed cdr and saves theevaluated value in place of thesuspension (promise).

Page 54: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

213CS 538 Spring 2003©

Given(define IL (inflist 1))

(head (tail IL)) returns 2 andexpands IL into

2 promise for(inflist 3)

1

214CS 538 Spring 2003©

Exploiting ParallelismConventional proceduralprogramming languages are difficultto compile for multiprocessors.Frequent assignments make itdifficult to find independentcomputations.Consider (in Fortran):

do 10 I = 1,1000 X(I) = 0 A(I) = A(I+1)+1 B(I) = B(I-1)-1 C(I) = (C(I-2) + C(I+2))/210 continue

This loop defines 1000 values forarrays X, A, B and C.

215CS 538 Spring 2003©

Which computations can be done inparallel, partitioning parts of an arrayto several processors, each operatingindependently?• X(I) = 0

Assignments to X can be readilyparallelized.

• A(I) = A(I+1)+1

Note that each computation of A(I)uses an A(I+1) value that is yet tobe changed. Thus a whole array ofnew A values can be computed froman array of “old” A values in parallel.

• B(I) = B(I-1)-1

This is less obvious. Each B(I) usesB(I-1) which is defined in terms ofB(I-2) , etc. Ultimately all new Bvalues depend only on B(0) and I .That is, B(I) = B(0) - I . So this

216CS 538 Spring 2003©

computation can be parallelized, butit takes a fair amount of insight torealize it.

• C(I) = (C(I-2) + C(I+2))/2

It is clear that even and odd elementsof C don’t interact. Hence twoprocessors could compute even andodd elements of C in parallel. Beyondthis, since both earlier and later Cvalues are used in each computationof an element, no further means ofparallel evaluation is evident. Serialevaluation will probably be neededfor even or odd values.

Page 55: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

217CS 538 Spring 2003©

Exploiting Parallelism inScheme

Assume we have a shared-memorymultiprocessor. We might be able toassign different processors toevaluate various independentsubexpressions.For example, consider(map (lambda(x) (* 2 x)) '(1 2 3 4 5))We might assign a processor to eachlist element and compute the lambdafunction on each concurrently:

1 2 3 4 5

2 4 6 8 10

Processor 1 Processor 5...

218CS 538 Spring 2003©

How is Parallelism Found?There are two approaches:• We can use a “smart” compiler that is

able to find parallelism in existingprograms written in standard serialprogramming languages.

• We can add features to an existingprogramming language that allows aprogrammer to show where parallelevaluation is desired.

219CS 538 Spring 2003©

ConcurrentizationConcurrentization (often calledparallelization) is process ofautomatically finding potentialconcurrent execution in a serialprogram.Automatically finding currentexecution is complicated by a numberof factors:• Data Dependence

Not all expressions are independent. Wemay need to delay evaluation of anoperator or subprogram until itsoperands are available.Thus in(+ (* x y) (* y z))

we can’t start the addition until bothmultiplications are done.

220CS 538 Spring 2003©

• Control DependenceNot all expressions need be (or shouldbe) evaluated.In(if (= a 0)

0

(/ b a))

we don’t want to do the division untilwe know a ≠ 0.

• Side EffectsIf one expression can write a value thatanother expression might read, weprobably will need to serialize theirexecution.Consider(define rand! (let ((seed 99)) (lambda () (set! seed (mod (* seed 1001) 101101)) seed)) )

Page 56: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

221CS 538 Spring 2003©

Now in(+ (f (rand!)) (g (rand!)))

we can’t evaluate (f (rand!)) and(g (rand!)) in parallel, because ofthe side effect of set! in rand! . Infact if we did, f and g might see exactlythe same “random” number! (Why?)

• GranularityEvaluating an expression concurrentlyhas an overhead (to setup a concurrentcomputation). Evaluating very simpleexpressions (like (car x) or(+ x 1) ) in parallel isn’t worth theoverhead cost.Estimating where the “break even”threshold is may be tricky.

222CS 538 Spring 2003©

Utility of ConcurrentizationConcurrentization has been mostsuccessful in engineering andscientific programs that are veryregular in structure, evaluating largemultidimensional arrays in simplenested loops. Many very complexsimulations (weather, fluid dynamics,astrophysics) are run onmultiprocessors after extensiveconcurrentization.Concurrentization has been far lesssuccessful on non-scientific programsthat don’t use large arraysmanipulated in nested for loops. Acompiler, for example, is difficult torun (in parallel) on a multiprocessor.

223CS 538 Spring 2003©

Reading Assignment• Roosta: Section 13.3

• Introduction to Standard ML (linked from class web page)

• Webber: Chapters 5, 7, 9, 11

224CS 538 Spring 2003©

Concurrentization withinProcessors

Concurrentization is used extensivelywithin many modern uniprocessors.Pentium and PowerPC processorsroutinely execute several instructionsin parallel if they are independent(e.g., read and write distinctregisters). This are superscalarprocessors.These processors also routinelyspeculate on execution paths,“guessing” that a branch will (orwon’t) be taken even before thebranch is executed! This allows formore concurrent execution than ifstrictly “in order” execution is done.These processors are called “out oforder” processors.

Page 57: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

225CS 538 Spring 2003©

Adding Parallel Features toProgramming Languages.

It is common to take an existing serialprogramming language and addfeatures that support concurrent orparallel execution. For exampleversions for Fortran (like HPF—HighPerformance Fortran) add a paralleldo loop that executes individualiterations in parallel.Java supports threads, which may beexecuted in parallel. Synchronizationand mutual exclusion are provided toavoid unintended interactions.

226CS 538 Spring 2003©

MultilispMultilisp is a version of Schemeaugmented with three parallelevaluation mechanisms:• Pcall

Arguments to a call are evaluated inparallel.

• FutureEvaluation of an expression startsimmediately. Rather than waiting forcompletion of the computation, a“future” is returned. This future willeventually transform itself into theresult value (when the computationcompletes)

• DelayEvaluation is delayed until the resultvalue is really needed.

227CS 538 Spring 2003©

The Pcall MechanismPcall is an extension to Scheme’sfunction call mechanism that causesthe function and its arguments to beall computed in parallel.Thus(pcall F X Y Z)

causes F, X, Y and Z to all beevaluated in parallel. When allevaluations are done, F is called withX, Y and Z as its parameters (just as inordinary Scheme).Compare(+ (* X Y) (* Y Z))

with(pcall + (* X Y) (* Y Z))

228CS 538 Spring 2003©

It may not look like pcall can giveyou that much parallel execution, butin the context of recursive definitions,the effect can be dramatic.Consider treemap , a version of mapthat operates on binary trees(S-expressions).(define (treemap fct tree)

(if (pair? tree)

(pcall cons

(treemap fct (car tree))

(treemap fct (cdr tree))

)

(fct tree)

))

Look at the execution of treemap onthe tree (((1 . 2) . (3 . 4)) .

((5 . 6) . (7 . 8)))

Page 58: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

229CS 538 Spring 2003©

We start with one call that uses thewhole tree. This splits into twoparallel calls, one operating on((1 . 2) . (3 . 4))

and the other operating on((5 . 6) . (7 . 8))

Each of these calls splits into 2 calls,and finally we have 8 independentcalls, each operating on the values 1to 8.

230CS 538 Spring 2003©

FuturesEvaluation of an expression as afuture is the most interesting featureof Multilisp.The call(future expr)

begins the evaluation of expr .But rather than waiting for expr ’sevaluation to complete, the call tofuture returns immediately with anew kind of data object—a future.This future is actually an “IOU.” Whenyou try to use the value of the future,the computation of expr may or maynot be completed. If it is, you see thevalue computed instead of thefuture—it automatically transformsitself. Thus evaluation of exprappears instantaneous.

231CS 538 Spring 2003©

If the computation of expr is not yetcompleted, you are forced to waituntil computation is completed. Thenyou may use the value and resumeexecution.But this is exactly what ordinaryevaluation does anyway—you beginevaluation of expr and wait untilevaluation completes and returns avalue to you!

232CS 538 Spring 2003©

To see the usefulness of futures,consider the usual definition ofScheme’s map function:(define (map f L) (if (null? L) () (cons (f (car L)) (map f (cdr L))) ))

If we have a call(map slow-function long-list)

where slow-function executesslowly and long-list is a large datastructure, we can expect to wait quitea while for computation of the resultlist to complete.

Page 59: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

233CS 538 Spring 2003©

Now consider fastmap , a version ofmap that uses futures:(define (fastmap f L) (if (null? L) () (cons (future (f (car L))) (fastmap f (cdr L)) ) ))

Now look at the call(fastmap slow-function long-list)

We will exploit a useful aspect offutures—they can be cons’ed togetherwithout delay, even if thecomputation isn’t completed yet.Why? Well a cons just stores a pairof pointers, and it really doesn’tmatter what the pointers reference (afuture or an actual result value).

234CS 538 Spring 2003©

The call to fastmap can actuallyreturn before any of the call to slow-function have completed:

Eventually all the futuresautomatically transform themselvesinto data values:

future1

future2

future3 ...

answer1

answer2

answer3 ...

235CS 538 Spring 2003©

Note that pcall can be implementedusing futures.That is, instead of(pcall F X Y Z)

we can use((future F) (future X) (future Y) (future Z))

In fact the latter version is actuallymore parallel—execution of F canbegin even if all the parameters aren’tcompletely evaluated.

236CS 538 Spring 2003©

Another Example of FuturesThe following function, partition ,will take a list and a data value(called pivot ). partition willpartition the list into two sublists:(a) Those elements ≤ pivot

(b) Those elements > pivot(define (partition pivot L) (if (null? L) (cons () () ) (let ((tail-part

(partition pivot (cdr L)))) (if (<= (car L) pivot) (cons

(cons (car L) (car tail-part))(cdr tail-part))

(cons(car tail-part))(cons (car L) (cdr tail-part))

)) ) )

Page 60: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

237CS 538 Spring 2003©

We want to add futures to partition,but where?It makes sense to use a future when acomputation may be lengthy and wemay not need to use the valuecomputed immediately.What computation fits that pattern?The computation of tail-part . We’llmark it in a blue box to show we planto evaluate it using a future:

238CS 538 Spring 2003©

(define (partition pivot L) (if (null? L) (cons () () ) (let ((tail-part

(partition pivot (cdr L)))) (if (<= (car L) pivot) (cons

(cons (car L) (car tail-part))(cdr tail-part))

(cons(car tail-part))(cons (car L) (cdr tail-part))

)) ) )

But this one change isn’t enough! Wesoon access the car and cdr oftail-part , which forces us to waitfor its computation to complete. Toavoid this delay, we can place thefour references to car or cdr oftail-part into futures too:

239CS 538 Spring 2003©

(define (partition pivot L) (if (null? L) (cons () () ) (let ((tail-part

(partition pivot (cdr L)))) (if (<= (car L) pivot) (cons

(cons (car L) (car tail-part))(cdr tail-part))

(cons(car tail-part))(cons (car L) (cdr tail-part))

)) ) )

240CS 538 Spring 2003©

Now we can build the initial part ofthe partitioned list (that involvingpivot and (car L) independently ofthe recursive call of partition ,which completes the rest of the list.For example,(partition 17 '(5 3 8 ...))

creates a future (call it future1 ) tocompute(partition 17 '(3 8 ...))

It also creates future2 to compute(car tail-part) and future3 tocompute (cdr tail-part) . The callbuilds

5 future2

future3

Page 61: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

241CS 538 Spring 2003©

ML—Meta LanguageSML is Standard ML, a popular MLvariant.ML is a functional language that isdesigned to be efficient and type-safe. It demonstrates that afunctional language need not useScheme’s odd syntax and need notbear the overhead of dynamic typing.SML’s features and innovationsinclude:1. Strong, compile-time typing.2. Automatic type inference rather

than user-supplied typedeclarations.

3. Polymorphism, including “typevariables.”

242CS 538 Spring 2003©

4. Pattern-directed Programmingfun len([]) = 0

| len(a::b) = 1+len(b);

5. Exceptions6. First-class functions7. Abstract Data Types coin of int |

bill of int |check of string*real;val dime = coin(10);

A good ML reference is“Elements of ML Programming,”by Jeffrey Ullman(Prentice Hall, 1998)

243CS 538 Spring 2003©

SML is InteractiveYou enter a definition or expression,and SML returns a result with aninferred type.The command use "file name";

loads a set of ML definitions from afile.For example (SML responses are inblue):21;val it = 21 : int

(2 div 3);val it = 0 : int

true;val it = true : bool

"xyz";val it = "xyz" : string

244CS 538 Spring 2003©

Basic SML Predefined Types• Unit

Its only value is () . Type unit issimilar to void in C; it is used wherea type is needed, but no “real” type isappropriate. For example, a call to awrite function may return unit as itsresult.

• IntegerConstants are sequences of digits.Negative values are prefixed with a ~rather than a - (- is a binarysubtraction operator). For example,~123 is negative 123 .Standard operators include+ - * div mod< > <= >= = <>

Page 62: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

245CS 538 Spring 2003©

• RealBoth fractional (123.456 ) andexponent forms (10e7 ) are allowed.Negative signs and exponents use ~rather than - (~10.0e~12 ).Standard operators include+ - * /< > <= >=

Note that = and <> aren’t allowed!(Why?)Conversion routines includereal(int) to convert an int to areal ,floor(real) to take the floor of areal ,ceil(real) to take the ceiling of areal .round(real) to round a real ,trunc(real) to truncate a real .

246CS 538 Spring 2003©

For example, real(3) returns 3.0 ,floor(3.1) returns 3,ceiling(3.3) returns 4,round(~3.6) returns ~4,trunc(3.9) returns 3.Mixed mode expressions, like1 + 2.5 aren’t allowed; you must doexplicit conversion, likereal(1) + 2.5

• StringsStrings are delimited by doublequotes. Newlines are \n , tabs are \t ,and \" and \\ escape double quotesand backslashes. E.g. "Bye now\n"The ^ operator is concatenation."abc" ^ "def" = "abcdef"

The usual relation operators areprovided: < > <= >= = <>

247CS 538 Spring 2003©

• CharactersSingle characters are delimited bydouble quotes and prefixed by a #.For example, #"a" or #"\t" . Acharacter is not a string of length one.The str function may be used toconvert a character into a string. Thusstr(#"a") = "a"

• BooleanConstants are true and false .Operators include andalso (short-circuit and), orelse (short-circuitor), not , = and <>.A conditional expression,(if boolval v 1 else v 2) isavailable.

248CS 538 Spring 2003©

TuplesA tuple type, composed of two ormore values of any type is available.Tuples are delimited by parentheses,and values are separated by commas.Examples include:(1,2);val it = (1,2) : int * int

("xyz",1=2);val it = ("xyz",false) : string * bool

(1,3.0,false);val it = (1,3.0,false) : int * real * bool

(1,2,(3,4));val it = (1,2,(3,4)) :int * int * (int * int)

Page 63: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

249CS 538 Spring 2003©

Equality is checked componentwise:(1,2) = (0+1,1+1);val it = true : bool

(1,2,3) = (1,2) causes a compile-time type error (tuples must be of thesame length and have correspondingtypes to be compared).#i selects the i -th component of atuple (counting from 1). Hence#2(1,2,3);val it = 2 : int

250CS 538 Spring 2003©

ListsLists are required to have a singleelement type for all their elements;their length is unbounded.Lists are delimited by [ and ] andelements are separated by commas.Thus [1,2,3] is an integer list. Theempty (or null) list is [] or nil .The cons operator is ::

Hence [1,2,3] ≡ 1::2::3::[]

Lists are automatically typed by ML:[1,2];val it = [1,2] : int list

251CS 538 Spring 2003©

ConsCons is an infix operator representedas ::

The left operand of :: is any value oftype T.The right operand of :: is any list oftype T list .The result of :: is a list of typeT list .

Hence :: is polymorphic.[] is the empty list. It has a type'a list . The symbol 'a , read as“alpha” or “tic a” is a type variable.Thus [] is a polymorphic constant.

252CS 538 Spring 2003©

List EqualityTwo lists may be compared forequality if they are of the same type.Lists L1 and L2 are considered equalif:(1) They have the same number of elements(2) Corresponding members of the two lists are equal.

List Operatorshd ≡ head of list operator ≈ car

tl ≡ tail of list operator ≈ cdr

null ≡ null list predicate ≈ null?

@≡ infix list append operator ≈append

Page 64: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

253CS 538 Spring 2003©

RecordsTheir general form is{name 1=val 1, name 2=val 2, ... }

Field selector names are local to arecord.For example:{a=1,b=2};

val it = {a=1,b=2} : {a:int, b:int}

{a=1,b="xyz"};val it = {a=1,b="xyz"} : {a:int, b:string}

{a=1.0,b={c=[1,2]}};val it = {a=1.0,b={c=[1,2]}} :{a:real, b:{c:int list}}

254CS 538 Spring 2003©

The order of fields is irrelevant;equality is tested using field names.{a=1,b=2}={b=2,a=2-1};val it = true : bool

#id extracts the field named id froma record.#b {a=1,b=2} ;

val it = 2 : int

255CS 538 Spring 2003©

IdentifiersThere are two forms:• Alphanumeric (excluding reserved words)

Any sequence of letters, digits, singlequotes and underscores; must beginwith a letter or single quote.Case is significant. Identifiers thatbegin with a single quote are typevariables.Examples include:abc a10 'polar sum_of_20

• SymbolicAny sequence (except predefinedoperators) of! % & + - / : < = > ? @ \ ~ ^ | # *

Usually used for user-definedoperators.Examples include: ++ <=> !=

256CS 538 Spring 2003©

CommentsOf form(* text *)

May cross line boundaries.

Declaration of ValuesThe basic form isval id = expression;

This defines id to be bound toexpression ; ML answers with thename and value defined and theinferred type.For exampleval x = 10*10;val x = 100 : int

Page 65: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

257CS 538 Spring 2003©

Redefinition of an identifier is OK,but this is redefinition notassignment;Thusval x = 100;

val x = (x=100);

is fine; there is no type error eventhough the first x is an integer andthen it is a boolean.val x = 100 : int

val x = true : bool

258CS 538 Spring 2003©

Examplesval x = 1;val x = 1 : int

val z = (x,x,x);val z = (1,1,1) : int * int * int

val L = [z,z];val L = [(1,1,1),(1,1,1)] : (int * int * int) list

val r = {a=L};val r = {a=[(1,1,1),(1,1,1)]} :{a:(int * int * int) list}

After rebinding, the “nearest” (mostrecent) binding is used.

259CS 538 Spring 2003©

The and symbol (not boolean and) isused for simultaneous binding:val x = 10;val x = 10 : int

val x = true and y = x;val x = true : bool

val y = 10 : int

Local definitions are temporary valuedefinitions:local

val x = 10

in

val u = x*x;

end;val u = 100 : int

260CS 538 Spring 2003©

Let bindings are used in expressions:let

val x = 10

in 5*x

end;val it = 50 : int

Page 66: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

261CS 538 Spring 2003©

PatternsIn Scheme (and most otherlanguages) we need access ordecomposition functions to access thecomponents of a structured object.Thus we might have(let ( (h (car L) (t (cdr L)) )

body )

Here car and cdr are used as accessfunctions to locate the parts of L wewant to access.In ML, we can access components oflists (or tuples, or records) directly byusing patterns. The context in whichthe identifier appears tells us the partof the structure it references.

262CS 538 Spring 2003©

val x = (1,2);val x = (1,2) : int * int

val (h,t) = x;val h = 1 : int

val t = 2 : int

val L = [1,2,3];val L = [1,2,3] : int list

val [v1,v2,v3] = L;val v1 = 1 : int

val v2 = 2 : int

val v3 = 3 : int

val [1,x,3] = L;val x = 2 : int

val [1,rest] = L;(* This is illegal. Why? *)

val yy::rest = L;val yy = 1 : int

val rest = [2,3] : int list

263CS 538 Spring 2003©

WildcardsAn underscore (_) may be used as a“wildcard” or “don’t care” symbol. Itmatches part of a structure withoutdefining an new binding.val zz::_ = L;val zz = 1 : int

Pattern matching works in recordstoo.val r = {a=1,b=2};val r = {a=1,b=2} : {a:int, b:int}

val {a=va,b=vb} = r;val va = 1 : int

val vb = 2 : int

val {a=wa,b=_}=r;val wa = 1 : int

val {a=za, ...}=r;val za = 1 : int

264CS 538 Spring 2003©

Patterns can be nested too.val x = ((1,3.0),5);val x = ((1,3.0),5) : (int * real) * int

val ((1,y),_)=x;val y = 3.0 : real

Page 67: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

265CS 538 Spring 2003©

FunctionsFunctions take a single argument(which can be a tuple).Function calls are of the formfunction_name argument;

For examplesize "xyz";

cos 3.14159;

The more conventional formsize("xyz"); or cos(3.14159);

is OK (the parentheses around theargument are allowed, butunnecessary).The form (size "xyz") or(cos 3.14159)

is OK too.

266CS 538 Spring 2003©

Note that the callplus(1,2);

passes one argument, the tuple (1,2)

to plus .The call dummy();

passes one argument, the unit value,to dummy.All parameters are passed by value.

267CS 538 Spring 2003©

Function TypesThe type of a function in ML isdenoted as T1->T2 . This says that aparameter of type T1 is mapped to aresult of type T2.The symbol fn denotes a value that isa function.Thussize;val it = fn : string -> int

not;val it = fn : bool -> bool

Math.cos;val it = fn : real -> real

(Math is an ML structure—an externallibrary member that containsseparately compiled definitions).

268CS 538 Spring 2003©

User-Defined FunctionsThe general form isfun name arg = expression;

ML answers back with the namedefined, the fact that it is a function(the fn symbol) and its inferred type.For example,fun twice x = 2*x;val twice = fn : int -> int

fun twotimes(x) = 2*x;val twotimes = fn : int -> int

fun fact n =

if n=0

then 1

else n*fact(n-1);val fact = fn : int -> int

Page 68: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

269CS 538 Spring 2003©

fun plus(x,y) :int = x+y;val plus = fn : int * int -> int

The :int suffix is a type constraint.It is needed to help ML decide that +is integer plus rather than real plus.

270CS 538 Spring 2003©

Patterns In FunctionDefinitions

The following defines a predicate thattests whether a list, L is null (thepredefined null function alreadydoes this).fun isNull L = if L=[] then true elsefalse;val isNull = fn : 'a list -> bool

However, we can decompose thedefinition using patterns to get asimpler and more elegant definition: fun isNull [] = true

| isNull(_::_) = false;val isNull = fn : 'a list -> bool

271CS 538 Spring 2003©

The “| ” divides the functiondefinition into different argumentpatterns; no explicit conditional logicis needed. The definition that matchesa particular actual parameter isautomatically selected.fun fact(1) = 1

| fact(n) = n*fact(n-1);val fact = fn : int -> int

If patterns that cover all possiblearguments aren’t specified, you mayget a run-time Match exception.If patterns overlap you may get awarning from the compiler.

272CS 538 Spring 2003©

fun append([],L) = L

| append(hd::tl,L) =hd::append(tl,L);

val append = fn : 'a list * 'a list -> 'a list

If we add the patternappend(L,[]) = L

we get a redundant pattern warning(Why?)fun append ([],L) = L

| append(hd::tl,L) =hd::append(tl,L)

| append(L,[]) = L;stdIn:151.1-153.20 Error: matchredundant

(nil,L) => ...

(hd :: tl,L) => ...

--> (L,nil) => ...

Page 69: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

273CS 538 Spring 2003©

But a more precise decomposition isfine:fun append ([],L) = L

| append(hd::tl,hd2::tl2) = hd::append(tl,hd2::tl2)

| append(hd::tl,[]) = hd::tl;val append = fn : 'a list * 'a list -> 'a list

274CS 538 Spring 2003©

Function Types Can bePolytypes

Recall that 'a , 'b , ... represent typevariables. That is, any valid type maybe substituted for them whenchecking type correctness.ML said the type of append isval append = fn : 'a list * 'a list -> 'a list

Why does 'a appear in three places?We can define eitherNull , apredicate that determines whethereither of two lists is null asfun eitherNull(L1,L2) = null(L1) orelse null(L2);val eitherNull = fn : ’a list * ’b list -> bool

Why are both 'a and 'b used ineitherNull ’s type?

275CS 538 Spring 2003©

CurryingML chooses the most general (least-restrictive) type possible for user-defined functions.Functions are first-class objects, as inScheme.The function definitionfun f x y = expression;

defines a function f (of x) thatreturns a function (of y).Reducing multiple argumentfunctions to a sequence of oneargument functions is called currying(after Haskell Curry, a mathematicianwho popularized the approach).

276CS 538 Spring 2003©

Thusfun f x y = x :: [y];val f = fn : 'a -> 'a -> 'a list

says that f takes a parameter x , oftype 'a , and returns a function (of y,whose type is 'a ) that returns a listof 'a .Contrast this with the moreconventionalfun g(x,y) = x :: [y];val g = fn : 'a * 'a -> 'a list

Here g takes a pair of arguments(each of type 'a ) and returns a valueof type 'a list.The advantage of currying is that wecan bind one argument and leave theremaining argument(s) free.

Page 70: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

277CS 538 Spring 2003©

For examplef(1);

is a legal call. It returns a function oftypefn : int -> int list

The function returned is equivalent tofun h b = 1 :: [b];val h = fn : int -> int list

278CS 538 Spring 2003©

Map RevisitedML supports the map function, whichcan be defined asfun map(f,[]) = [] | map(f,x::y) = (f x) :: map(f,y);val map =fn : ('a -> 'b) * 'a list -> 'b list

This type says that map takes a pair ofarguments. One is a function fromtype 'a to type 'b . The secondargument is a list of type 'a . Theresult is a list of type 'b .In curried form map is defined asfun map f [] = [] | map f (x::y) = (f x) :: map f y;val map = fn : ('a -> 'b) -> 'a list -> 'b list

279CS 538 Spring 2003©

This type says that map takes oneargument that is a function from type'a to type 'b . It returns a functionthat takes an argument that is a listof type 'a and returns a list of type'b .The advantage of the curried form ofmap is that we can now use map tocreate “specialized” functions inwhich the function that is mapped isfixed.For example,val neg = map not;val neg = fn : bool list -> bool list

neg [true,false,true];val it = [false,true,false] : bool list

280CS 538 Spring 2003©

Power Sets RevisitedLet’s compute power sets in ML.We want a function pow that takes alist of values, viewed as a set, andwhich returns a list of lists. Eachsublist will be one of the possiblesubsets of the original argument.For example,pow [1,2] = [[1,2],[1],[2],[]]

We first define a version of cons incurried form:fun cons h t = h::t;val cons = fn : 'a -> 'a list -> 'a list

Page 71: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

281CS 538 Spring 2003©

Now we define pow. We define thepowerset of the empty list, [] , to be[[]] . That is, the power set of theempty set is set that contains onlythe empty set.For a non-empty list, consisting ofh::t , we compute the power set of t ,which we call pset . Then the powerset for h::t is just h distributedthrough pset appended to pset .We distribute h through pset veryelegantly: we just map the function(cons h) to pset . (cons h) adds hto the head of any list it is given.Thus mapping (cons h) to psetadds h to all lists in pset .

282CS 538 Spring 2003©

The complete definition is simplyfun pow [] = [[]]

| pow (h::t) =

let

val pset = pow t

in

(map (cons h) pset) @ pset

end;val pow = fn : 'a list -> 'a list list

Let’s trace the computation ofpow [1,2] .Here h = 1 and t = [2] . We need tocompute pow [2] .Now h = 2 and t = [] .We know pow [] = [[]] ,so pow [2] =(map (cons 2) [[]])@[[]] =([[2]])@[[]] = [[2],[]]

283CS 538 Spring 2003©

Therefore pow [1,2] =

(map (cons 1) [[2],[]])@[[2],[]] =

[[1,2],[1]]@[[2],[]] =[[1,2],[1],[2],[]]

284CS 538 Spring 2003©

Composing FunctionsWe can define a composition functionthat composes two functions intoone:fun comp (f,g)(x) = f(g(x));val comp = fn :('a -> 'b) * ('c -> 'a) -> 'c -> 'b

In curried form we havefun comp f g x = f(g(x));val comp = fn :('a -> 'b) ->('c -> 'a) -> 'c -> 'b

For example,fun sqr x :int = x*x;

val sqr = fn : int -> int

comp sqr sqr;val it = fn : int -> int

Page 72: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

285CS 538 Spring 2003©

comp sqr sqr 3;val it = 81 : int

In SML o (lower-case O) is the infixcomposition operator.Hencesqr o sqr ≡ comp sqr sqr

286CS 538 Spring 2003©

Lambda TermsML needs a notation to write downunnamed (anonymous) functions,similar to the lambda expressionsScheme uses.That notation isfn arg => body;

For example,val sqr = fn x :int => x*x;val sqr = fn : int -> int

In fact the notation used to definefunctions,fun name arg = body;

is actually just an abbreviation for themore verboseval name = fn arg => body;

287CS 538 Spring 2003©

An anonymous function can be usedwherever a function value is needed.For example,map (fn x => [x]) [1,2,3];val it =[[1],[2],[3]] : int list list

We can use patterns too:(fn [] => [] |(h::t) => h::h::t);val it = fn : 'a list -> 'a list

(What does this function do?)

288CS 538 Spring 2003©

Polymorphism vs. OverloadingML supports polymorphism.A function may accept a polytype (aset of types) rather than a singlefixed type.In all cases, the same functiondefinition is used. Details of thesupplied type are irrelevant and maybe ignored.For example,fun id x = x;val id = fn : 'a -> 'a

fun toList x = [x];val toList = fn : 'a -> 'a list

Page 73: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

289CS 538 Spring 2003©

Overloading, as in C++ and Java,allows alternative definitions of thesame method or operator, withselection based on type.Thus in Java + may represent integeraddition, floating point addition orstring concatenation, even thoughthese are really rather differentoperations.In ML +, - , * and = are overloaded.When = is used (to test equality), MLdeduces that an equality type isrequired. (Most, but not all, types canbe compared for equality).When ML decides an equality type isneeded, it uses a type variable thatbegins with two tics rather than one.fun eq(x,y) = (x=y);val eq = fn : ''a * ''a -> bool

290CS 538 Spring 2003©

Defining New Types in MLWe can create new names for existingtypes (type abbreviations) usingtype id = def;

For example,type triple = int*real*string;type triple = int * real * string

type rec1= {a:int,b:real,c:string};type rec1 = {a:int, b:real, c:string}

type 'a triple3 = 'a*'a*'a;type 'a triple3 = 'a * 'a * 'a

type intTriple = int triple3;type intTriple = int triple3

These type definitions are essentialitymacro-like name substitutions.

291CS 538 Spring 2003©

The Datatype MechanismNew types are defined using thedatatype mechanism, whichspecifies new data value constructors.For example,datatype color = red|blue|green;datatype color = blue | green | red

Pattern matching works on user-defined types using theirconstructors:fun translate red = "rot" | translate blue = "blau" | translate green = "gruen";val translate = fn : color -> string

292CS 538 Spring 2003©

fun jumble red = blue | jumble blue = green | jumble green = red;val jumble = fn : color -> color

translate (jumble green);val it = "rot" : string

SML ExamplesSource code for most of the SMLexamples presented here may befound in~cs538-1/public/sml/class.sml

Page 74: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

293CS 538 Spring 2003©

Parameterized ConstructorsThe constructors used to define datatypes may be parameterized:datatype money = none | coin of int

| bill of int

| iou of real * string;datatype money = bill of int | coin of int | iou of real * string | none

Now expressions like coin(25) orbill(5) or iou(10.25,"Andy")represent valid values of type money.

294CS 538 Spring 2003©

We can also define values andfunctions of type money:val dime = coin(10);val dime = coin 10 : money

val deadbeat =iou(25.00,"Homer Simpson");val deadbeat = iou (25.0,"Homer Simpson") : money

fun amount(none) = 0.0

| amount(coin(cents)) = real(cents)/100.0

| amount(bill(dollars)) = real(dollars)

| amount(iou(amt,_)) = 0.5*amt; val amount = fn : money -> real

295CS 538 Spring 2003©

Polymorphic DatatypesA user-defined data type may bepolymorphic. An excellent example isdatatype 'a option = none | some of 'a;datatype 'a option = none | some of 'a

val zilch = none;val zilch = none : ’a option

val mucho =some(10e10);val mucho =some 100000000000.0 : real option

type studentInfo = {name:string, ssNumber:int option};type studentInfo = {name:string,ssNumber:int option}

296CS 538 Spring 2003©

val newStudent ={name="Mystery Man", ssNumber=none} :studentInfo ;val newStudent ={name="Mystery Man", ssNumber=none} : studentInfo

Page 75: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

297CS 538 Spring 2003©

Datatypes may be RecursiveRecursive datatypes allow linkedstructures without explicit pointers.datatype binTree = null| leaf

| node of binTree * binTree;datatype binTree =

leaf | node of binTree * binTree | null

fun size(null) = 0

| size(leaf) = 1

| size(node(t1,t2)) = size(t1)+size(t2) + 1val size = fn : binTree -> int

298CS 538 Spring 2003©

Recursive Datatypes may bePolymorphic

datatype 'a binTree = null| leaf of 'a| node of 'a binTree * 'a binTree

datatype 'a binTree = leaf of 'a | node of 'a binTree * 'a binTree | null

fun frontier(null) = [] | frontier(leaf(v)) = [v] | frontier(node(t1,t2)) = frontier(t1) @ frontier(t2)

val frontier = fn : 'a binTree -> ’a list

299CS 538 Spring 2003©

We can model n-ary trees by usinglists of subtrees:datatype 'a Tree = null| leaf of 'a| node of 'a Tree list;datatype 'a Tree = leaf of 'a |node of 'a Tree list | null

fun frontier(null) = []

| frontier(leaf(v)) = [v]

| frontier(node(h::t)) = frontier(h) @

frontier(node(t))

| frontier(node([])) = []val frontier = fn : 'a Tree -> 'a list

300CS 538 Spring 2003©

Abstract Data TypesML also provides abstract data typesin which the implementation of thetype is hidden from users.The general form isabstype name = implementation

with

val and fun definitions

end;

Users may access the name of theabstract type and the val and fundefinitions that follow the with , butthe implementation may be usedonly with the body of the abstypedefinition.

Page 76: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

301CS 538 Spring 2003©

Exampleabstype 'a stack = stk of 'a list

with

val Null = stk([])

fun empty(stk([])) = true

| empty(stk(_::_)) = false

fun top(stk(h::_)) = h fun pop(stk(_::t)) = stk(t) fun push(v,stk(L)) = stk(v::L)

endtype 'a stack

val Null = - : 'a stack

val empty = fn : 'a stack -> bool

val top = fn : 'a stack -> 'a

val pop = fn : 'a stack -> 'a stack

val push = fn : 'a * 'a stack -> 'a stack

302CS 538 Spring 2003©

Local value and function definitions,not to be exported to users of thetype can be created using the localdefinition mechanism describedearlier:local

val and fun definitions

in

exported definitions

end;

303CS 538 Spring 2003©

abstype 'a stack = stk of 'a listwith local fun size(stk(L))=length(L); in val Null = stk([]) fun empty(s) = (size(s) = 0)

fun top(stk(h::_)) = h fun pop(stk(_::t)) = stk(t) fun push(v,stk(L)) = stk(v::L) endendtype 'a stackval Null = - : 'a stackval empty = fn : 'a stack -> boolval top = fn : 'a stack -> 'aval pop = fn : 'a stack -> 'a stackval push = fn : 'a * 'a stack -> 'a stack

304CS 538 Spring 2003©

Why are abstract data types useful?Because they hide an implementationof a type from a user, allowingimplementation changes without anyimpact on user programs.Consider a simple implementation ofqueues:abstype 'a queue = q of 'a list

with

val Null = q([])

fun front(q(h::_)) = h fun rm(q(_::t)) = q(t) fun enter(v,q(L)) = q(rev(v::rev(L)))

endtype 'a queue

val Null = - : 'a queue

val front = fn : ’a queue -> 'a

Page 77: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

305CS 538 Spring 2003©

val rm = fn : 'a queue -> 'a queue

val enter = fn : 'a * 'a queue -> 'a queue

This implementation of queues isvalid, but somewhat inefficient. Inparticular to enter a new value ontothe rear end of a queue, we do thefollowing:fun enter(v,q(L)) = q(rev(v::rev(L)))

We reverse the list that implementsthe queue, add the new value to thehead of the reversed queue thenreverse the list a second time.

306CS 538 Spring 2003©

A more efficient (but less obvious)implementation of a queue is to storeit as two lists. One list represents the“front” of the queue. It is from thislist that we extract the front value,and from which we remove elements.The other list represents the “back” ofthe queue (in reversed order). We addelements to the rear of the queue byadding elements to the front of thelist. From time to time, when thefront list becomes null, we “promote”the rear list into the front list (byreversing it). Now access to both thefront and the back of the queue isfast and direct. The newimplementation is:

307CS 538 Spring 2003©

abstype 'a queue = q of 'a list * 'a list

with

val Null = q([],[])

fun front(q(h::_,_)) = h | front(q([],L)) = front(q(rev(L),[])) fun rm(q(_::t,L)) = q(t,L) | rm(q([],L)) = rm(q(rev(L),[])) fun enter(v,q(L1,L2)) = q(L1,v::L2)

end

type ' a queue

val Null = - : ' a queue

val front = fn :' a queue -> ' a

val rm = fn :' a queue -> ' a queue

val enter = fn :' a * ' a queue -> ' a queue

308CS 538 Spring 2003©

From the user’s point of view, the twoimplementations are identical (theyexport exactly the same set of valuesand functions). Hence the newimplementation can replace the oldimplementation without any impactat all to the user (except, of course,performance!).

Page 78: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

309CS 538 Spring 2003©

Exception HandlingOur definitions of stacks and queuesare incomplete. Reconsider ourdefinition of stack:abstype 'a stack = stk of 'a list

with

val Null = stk([])

fun empty(stk([])) = true

| empty(stk(_::_)) = false

fun top(stk(h::_)) = h fun pop(stk(_::t)) = stk(t) fun push(v,stk(L)) = stk(v::L)

end

What happens if we evaluatetop(Null);

We get a “match failure” because ourdefinition of top is incomplete!

310CS 538 Spring 2003©

In ML we can raise an exception if anillegal or unexpected operationoccurs. Asking for the top of anempty stack ought to raise anexception since the requested valuedoes not exist.ML contains a number of predefinedexceptions, includingMatch Empty Div Overflow

(exception names by conventionbegin with a capital letter).Predefined exception are raised byillegal values or operations. If theyare not caught, the run-time systemprints an error message.

311CS 538 Spring 2003©

fun f(1) = 2;val f = fn : int -> int

f(2);uncaught exception nonexhaustivematch failure

hd [];uncaught exception Empty

1000000*1000000;uncaught exception overflow

(1 div 0);uncaught exception divide by zero

1.0/0.0;

val it = inf : real

(inf is the IEEE floating-pointstandard “infinity” value)

312CS 538 Spring 2003©

User Defined ExceptionsNew exceptions may be defined asexception name;

orexception name of type;

For exampleexception IsZero;exception IsZero

exception NegValue of real;exception NegValue of real

Page 79: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

313CS 538 Spring 2003©

Exceptions May be RaisedThe raise statement raises (throws)an exception:raise exceptionName;

orraise exceptionName(expr);

For examplefun divide(a,0) = raise IsZero | divide(a,b) = a div b;val divide = fn : int * int -> int

divide(10,3);val it = 3 : int

divide(10,0);uncaught exception IsZero

314CS 538 Spring 2003©

val sqrt = Real.Math.sqrt;val sqrt = fn : real -> real

fun sqroot(x) = if x < 0.0 then raise NegValue(x) else sqrt(x);val sqroot = fn : real -> real

sqroot(2.0);val it = 1.41421356237 : real

sqroot(~2.0);uncaught exception NegValue

315CS 538 Spring 2003©

Exception HandlersYou may catch an exception bydefining a handler for it:(expr) handle exception1 => val1 || exception2 => val2 || ... ;

For example,(sqroot ~100.0) handle NegValue(v) => (sqrt (~v));val it = 10.0 : real

316CS 538 Spring 2003©

Stacks RevisitedWe can add an exception, EmptyStk ,to our earlier stack type to handletop or pop operations on an emptystack:abstype 'a stack = stk of 'a listwith val Null = stk([]) exception EmptyStk fun empty(stk([])) = true | empty(stk(_::_)) = false fun top(stk(h::_)) = h | top(stk([])) = raise EmptyStk fun pop(stk(_::t)) = stk(t) | pop(stk([])) = raise EmptyStk fun push(v,stk(L)) = stk(v::L)end

Page 80: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

317CS 538 Spring 2003©

type 'a stackval Null = - : 'a stackexception EmptyStkval empty = fn : 'a stack -> boolval top = fn : 'a stack -> 'aval pop = fn : 'a stack -> 'a stackval push = fn : 'a * 'a stack ->'a stack

pop(Null);uncaught exception EmptyStktop(Null) handle EmptyStk => 0;val it = 0 : int

318CS 538 Spring 2003©

User-Defined OperatorsSML allows users to define symbolicoperators composed of non-alphanumeric characters. This meansoperator-like symbols can be createdand used. Care must be taken to avoidpredefined operators (like +, - , ^ , @,etc.).If we wish, we can redo our stackdefinition using symbols rather thanidentifiers.We might choose the followingsymbols:top |=

pop <==

push ==>

null <@>

empty <?>

319CS 538 Spring 2003©

Now we can have expressions like<?> <@>;val it = true : bool

|= (==> (1,<@>));val it = 1 : int

Binary functions, like ==> (push) aremuch more readable if they are infix.That is, we’d like to be able to write1 ==> 2+3 ==> <@>

which pushes 2+3 , then 1 onto anempty stack.To make a function (either identifieror symbolic) infix rather than prefixwe use the definitioninfix level name

orinfixr level name

320CS 538 Spring 2003©

level is an integer representing the“precedence” level of the infixoperator. 0 is the lowest precedencelevel; higher precedence operators areapplied before lower precedenceoperators (in the absence of explicitparentheses).infix defines a left-associativeoperator (groups from left to right).infixr defines a right-associativeoperator (groups from right to left).Thusfun cat(L1,L2) = L1 @ L2;

infix 5 cat

makes cat a left associative infixoperator at the same precedence levelas @. We can now write[1,2] cat [3,4,5] cat [6,7];val it = [1,2,3,4,5,6,7] : int list

Page 81: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

321CS 538 Spring 2003©

The standard predefined operatorshave the following precedence levels:Level Operator3 o

4 = <> < > <= >=

5 :: @

6 + - ^

7 * / div mod

If we define ==> (push) asinfixr 2 ==>

then1 ==> 2+3 ==> <@>

will work as expected, evaluatingexpressions like 2+3 before doing anypushes, with pushes done right toleft.

322CS 538 Spring 2003©

abstype 'a stack = stk of 'a list

with

val <@> = stk([])

exception emptyStk

fun <?>(stk([])) = true

| <?>(stk(_::_)) = false

fun |=(stk(h::_)) = h

| |=(stk([])) = raise emptyStk

fun <==(stk(_::t)) = stk(t)

| <==(stk([])) = raise emptyStk

fun ==>(v,stk(L)) = stk(v::L)

infixr 2 ==>

end

323CS 538 Spring 2003©

type 'a stack

val <@> = - : 'a stack

exception emptyStk

val <?> = fn : 'a stack -> bool

val |= = fn : 'a stack -> 'a

val <== = fn : 'a stack -> 'a stack

val ==> = fn : ’a * 'a stack ->'a stack

infixr 2 ==>

Now we can writeval myStack = 1 ==> 2+3 ==> <@>;val myStack = - : int stack

|= myStack;val it = 1 : int

|= (<== myStack);val it = 5 : int

324CS 538 Spring 2003©

Using Infix Operators asValues

Sometimes we simply want to use aninfix operator as a symbol whosevalue is a function.For example, givenfun dupl f v = f(v,v);val dupl =

fn : ('a * 'a -> 'b) -> 'a -> 'b

we might try the calldupl ^ "abc";

This fails because SML tries to parsedupl and "abc" as the operands of ^ .To pass an operator as an ordinaryfunction value, we prefix it with opwhich tells the SML compiler that thefollowing symbol is an infix operator.

Page 82: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

325CS 538 Spring 2003©

Thusdupl op ^ "abc";val it = "abcabc" : string

works fine.

326CS 538 Spring 2003©

The Case ExpressionML contains a case expressionpatterned on switch and casestatements found in other languages.As in function definitions, patternsare used to choose among a variety ofvalues.The general form of the case iscase expr of

pattern 1 => expr 1|

pattern n => expr 2|

...

pattern n => expr n;

If no pattern matches, a Matchexception is thrown.It is common to use _ (the wildcard)as the last pattern in a case .

327CS 538 Spring 2003©

Examples includecase c of

red => "rot" |

blue => "blau" |

green => "gruen";

case pair of

(1,_) => "win" |

(2,_) => "place" |

(3,_) => "show" |

(_,_) => "loser";

case intOption of

none => 0 |

some(v) => v;

328CS 538 Spring 2003©

Imperative Features of MLML provides references to heaplocations that may be updated. This isessentially the same as access to heapobjects via references (Java) orpointers (C and C++).The expressionref val

creates a reference to a heap locationinitialized to val. For example, ref 0; val it = ref 0 : int ref

The prefix operator ! fetches the valuecontained in a heap location (just as *dereferences a pointer in C or C++).Thus ! (ref 0); val it = 0 : int

Page 83: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

329CS 538 Spring 2003©

The expressionref := val

updates the heap location referencedby ref to contain val . The unit value,() , is returned.Henceval x = ref 0;val x = ref 0 : int ref

!x;val it = 0 : int

x:=1;val it = () : unit

!x;val it = 1 : int

330CS 538 Spring 2003©

Sequential CompositionExpressions or statements aresequenced using “; ”. Henceval a = (1+2;3+4);val a = 7 : int

(x:=1;!x);val it = 1 : int

Iterationwhile expr1 do expr2

implements iteration (and returnsunit); Thus(while false do 10);val it = () : unit

while !x > 0 do x:= !x-1;val it = () : unit

!x;val it = 0 : int

331CS 538 Spring 2003©

Simple I/OThe function print;

val it = fn : string -> unit

prints a string onto standard output.For example,print("Hello World\n");

Hello World

The conversion routines Real.toString; val it = fn : real -> string

Int.toString; val it = fn : int -> string

Bool.toString; val it = fn : bool -> string

convert a value (real , int or bool )into a string . Unlike Java, the callmust be explicit.

332CS 538 Spring 2003©

For example,print(Int.toString(123));123

Also available areReal.fromString;val it = fn : string -> realoption

Int.fromString;val it = fn : string -> intoption

Bool.fromString;val it = fn : string -> booloption

which convert from a string to areal or int or bool if possible.(That’s why the option type is used).

Page 84: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

333CS 538 Spring 2003©

For example,case (Int.fromString("123")) of

SOME(i) => i | NONE => 0;val it = 123 : int

case (Int.fromString( "One two three")) of

SOME(i) => i | NONE => 0;val it = 0 : int

334CS 538 Spring 2003©

Text I/OThe structure TextIO contains a widevariety of I/O types, values andfunctions. You load these by entering:open TextIO;

Among the values loaded are• type instream

This is the type that represents inputtext files.

• type outstreamThis is the type that representsoutput text files.

• type vector = stringMakes vector a synonym forstring.

• type elem = charMakes elem a synonym for char .

335CS 538 Spring 2003©

• val stdIn : instreamval stdOut : outstreamval stdErr : outstreamPredefined input and output streams.

• val openIn : string -> instreamval openOut : string -> outstreamOpen an input or output stream.For example,val out = openOut("/tmp/test1");val out = - : outstream

• val input : instream -> vectorRead a line of input into a string(vector is defined as equivalent tostring ). For example (user input isin red):

336CS 538 Spring 2003©

val s = input(stdIn);Hello!

val s = "Hello!\n" : vector

• val inputN : instream * int -> vectorRead the next N input characters intoa string . For example,val t = inputN(stdIn,3);abcde

val t = "abc" : vector

• val inputAll : instream -> vectorRead the rest of the input file into astring (with newlines separatinglines). For example,val u = inputAll(stdIn);

Four score and seven years ago ... val u = "Four score and\nseven years ago ...\n" : vector

Page 85: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

337CS 538 Spring 2003©

• val endOfStream : instream -> boolAre we at the end of this inputstream?

• val output : outstream * vector -> unitOutput a string on the specifiedoutput stream. For example,output(stdOut, "That’s all folks!\n");That’s all folks!

338CS 538 Spring 2003©

String OperationsML provides a wide variety of stringmanipulation routines. Included are:• The string concatenation operator, ^

"abc" ^ "def" = "abcdef"

• The standard 6 relational operators: < > <= >= = <>

• The string size operator:val size : string -> intsize ("abcd");val it = 4 : int

• The string subscripting operator(indexing from 0):val sub = fn : string * int -> charsub("abcde",2);val it = #"c" : char

339CS 538 Spring 2003©

• The substring functionval substring :string * int * int -> stringThis function is called assubstring(string,start,len)start is the starting position,counting from 0.len is the length of the desiredsubstring. For example,substring("abcdefghij",3,4)val it = "defg" : string

• Concatenation of a list of strings intoa single string:concat : string list -> stringFor example,concat ["What’s"," up","?"];val it = "What’s up?" : string

340CS 538 Spring 2003©

• Convert a character into a string:str : char -> stringFor example, str(#"x");

val it = "x" : string

• “Explode” a string into a list ofcharacters:explode : string -> char listFor example,explode("abcde");val it =[#"a",#"b",#"c",#"d",#"e"] :char list

• “Implode” a list of characters into astring.implode : char list -> stringFor example,implode[#"a",#"b",#"c",#"d",#"e"];val it = "abcde" : string

Page 86: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

341CS 538 Spring 2003©

Structures and SignaturesIn C++ and Java you can groupvariable and function definitions intoclasses. In Java you can also groupclasses into packages.In ML you can group value, exceptionand function definitions intostructures.You can then import selecteddefinitions from the structure (usingthe notation structure.name ) oryou can open the structure, therebyimporting all the definitions withinthe structure.(Examples used in this section may befound at~cs538-1/public/sml/struct.sml )

342CS 538 Spring 2003©

The general form of a structuredefinition isstructure name =struct

val, exception and fun definitions

end

For example,structure Mapping =struct exception NotFound; val create = []; fun lookup(key,[]) = raise NotFound | lookup(key, (key1,value1)::rest) = if key = key1 then value1 else lookup(key,rest);

343CS 538 Spring 2003©

fun insert(key,value,[]) = [(key,value)] | insert(key,value, (key1,value1)::rest) = if key = key1 then (key,value)::rest else (key1,value1):: insert(key,value,rest);end;

We can access members of thisstructure as Mapping.name . ThusMapping.insert(538,"languages",[]);

val it = [(538,"languages")] :(int * string) list

open Mapping;exception NotFound

val create : 'a list

val insert : ''a * 'b * (''a * 'b) list -> (''a * 'b) list

val lookup : ''a * (''a * 'b)list -> 'b

344CS 538 Spring 2003©

SignaturesEach structure has a signature, whichis it type.For example, Mapping ’s signature isstructure Mapping :

sig

exception NotFound

val create : 'a list

val insert : ''a * 'b * (''a * 'b) list -> (''a * 'b) list

val lookup : ''a * (''a * 'b) list -> 'b

end

Page 87: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

345CS 538 Spring 2003©

You can define a signature assignature name = sig

type definitions for values, functions and exceptions

end

For example,signature Str2IntMapping =sig exception NotFound; val lookup:

string * (string*int) list -> int;

end;

346CS 538 Spring 2003©

Signatures can be used to• Restrict the type of a value or

function in a structure.

• Hide selected definitions that appearin a structure

For examplestructure Str2IntMap :

Str2IntMapping = Mapping;

defines a new structure, Str2IntMap ,created by restricting Mapping to theStr2IntMapping signature. Whenwe do this we getopen Str2IntMap; exception NotFound

val lookup : string * (string * int) list -> int

Only lookup and NotFound arecreated, and lookup is limited to keysthat are strings.

347CS 538 Spring 2003©

Extending ML’s PolymorphismIn languages like C++ and Java wemust use types like void* or Objectto simulate the polymorphism thatML provides. In ML whenever possiblea general type (a polytype) is usedrather than a fixed type. Thus infun len([]) = 0

| len(a::b) = 1 + len(b);

we get a type of 'a list -> int

because this is the most general typepossible that is consistent with len ’sdefinition.Is this form of polymorphism generalenough to capture the general idea ofmaking program definitions as type-independent as possible?

348CS 538 Spring 2003©

It isn’t, and to see why consider thefollowing ML definition of a mergesort. A merge sort operates by firstsplitting a list into two equal lengthsublists. The following function doesthis:fun split [] = ([],[]) | split [a] = ([a],[]) | split (a::b::rest) = let val (left,right) = split(rest) in (a::left, b::right) end;

After the input list is split into twohalves, each half is recursively sorted,then the sorted halves are mergedtogether into a single list.The following ML function mergestwo sorted lists into one:

Page 88: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

349CS 538 Spring 2003©

fun merge([],[]) = [] | merge([],hd::tl) = hd::tl | merge(hd::tl,[]) = hd::tl | merge(hd::tl,h::t) = if hd <= h then hd::merge(tl,h::t) else h::merge(hd::tl,t)

With these two subroutines, adefinition of a sort is easy:fun sort [] = [] | sort([a]) = [a] | sort(a::b::rest) = let val (left,right) = split(a::b::rest) in merge(sort(left),

sort(right)) end;

350CS 538 Spring 2003©

This definition looks very general—itshould work for a list of any type.Unfortunately, when ML types thefunctions we get a surprise:val split = fn : 'a list -> 'a list * 'a listval merge = fn : int list * int list -> int listval sort = fn : int list -> int list

split is polymorphic, but merge andsort are limited to integer lists!Where did this restriction come from?

351CS 538 Spring 2003©

The problem is that we did acomparison in merge using the <=operator, and ML typed this as aninteger comparison.We can make our definition of sortmore general by adding a comparisonfunction, le(a,b) as a parameter tomerge and sort . If we curry thisparameter we may be able to hide itfrom end users. Our updateddefinitions are:fun merge(le,[],[]) = [] | merge(le,[],hd::tl) = hd::tl | merge(le,hd::tl,[]) = hd::tl | merge(le,hd::tl,h::t) = if le(hd,h) then hd::merge(le,tl,h::t) else h::merge(le,hd::tl,t)

352CS 538 Spring 2003©

fun sort le [] = [] | sort le [a] = [a] | sort le (a::b::rest) = let val (left,right) = split(a::b::rest) in merge(le, sort le left,

sort le right) end;

Now the types of merge and sortare:val merge = fn : ('a * 'a -> bool) * 'a list * 'a list -> 'a listval sort = fn : ('a * 'a -> bool) -> 'a list -> 'a list

We can now “customize” sort bychoosing a particular definition forthe le parameter:fun le(a,b) = a <= b;val le = fn : int * int -> bool

Page 89: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

353CS 538 Spring 2003©

fun intsort L = sort le L;val intsort = fn : int list -> int listintsort( [4,9,0,2,111,~22,8,~123]);val it = [~123,~22,0,2,4,8,9,111]: int list

fun strle(a:string,b) = a <= b;val strle = fn : string * string -> bool

fun strsort L = sort strle L;val strsort =

fn : string list -> string liststrsort( ["aac","aaa","ABC","123"]);val it =["123","ABC","aaa","aac"] :string list

354CS 538 Spring 2003©

Making the comparison relation anexplicit parameter works, but it is abit ugly and inefficient. Moreover, ifwe have several functions thatdepend on the comparison relation,we need to ensure that they all usethe same relation. Thus if we wish todefine a predicate inOrder that testsif a list is already sorted, we can use:fun inOrder le [] = true | inOrder le [a] = true | inOrder le (a::b::rest) = le(a,b) andalso inOrder le (b::rest);val inOrder = fn : ('a * 'a -> bool) -> 'a list -> bool

Now sort and inOrder need to usethe same definition of le . But howcan we enforce this?

355CS 538 Spring 2003©

The structure mechanism we studiedearlier can help. We can put a singledefinition of le in the structure, andshare it:structure Sorting =struct fun le(a,b) = a <= b;

fun split [] = ([],[]) | split [a] = ([a],[]) | split (a::b::rest) = let val (left,right) = split rest in

(a::left,b::right) end; fun merge([],[]) = [] | merge([],hd::tl) = hd::tl | merge(hd::tl,[]) = hd::tl | merge(hd::tl,h::t) = if le(hd,h) then hd::merge(tl,h::t) else h::merge(hd::tl,t)

356CS 538 Spring 2003©

fun sort [] = [] | sort([a]) = [a] | sort(a::b::rest) = let val (left,right) = split(a::b::rest) in merge(sort(left), sort(right)) end;

fun inOrder [] = true | inOrder [a] = true | inOrder (a::b::rest) = le(a,b) andalso inOrder (b::rest);end;

structure Sorting : sig

val inOrder : int list -> bool

val le : int * int -> bool

val merge : int list * int list -> int list

val sort : int list -> int list

Page 90: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

357CS 538 Spring 2003©

val split : 'a list -> 'a list * 'a list

end

To sort a type other than integers, wereplace the definition of le in thestructure.But rather than actually edit thatdefinition, ML gives us a powerfulmechanism to parameterize astructure. This is the functor, whichallows us to use one or morestructures as parameters in thedefinition of a structure.

358CS 538 Spring 2003©

FunctorsThe general form of a functor isfunctor name (structName:signature) = structure definition;

This functor will create a specificversion of the structure definitionusing the structure parameter passedto it.For our purposes this is ideal—we passin a structure defining an orderingrelation (the le function). This thencreates a custom version of all thefunctions defined in the structurebody, using the specific le definitionprovided.

359CS 538 Spring 2003©

We first definesignature Order =

sig

type elem

val le : elem*elem -> bool

end;

This defines the type of a structurethat defines a le predicate defined ona pair of types called elem .An example of such a structure isstructure IntOrder:Order =

struct

type elem = int;

fun le(a,b) = a <= b;

end;

Now we just define a functor thatcreates a Sorting structure based onan Order structure:

360CS 538 Spring 2003©

functor MakeSorting(O:Order) =struct

open O; (* makes le available*) fun split [] = ([],[]) | split [a] = ([a],[]) | split (a::b::rest) = let val (left,right) = split rest in (a::left,b::right) end;

fun merge([],[]) = [] | merge([],hd::tl) = hd::tl | merge(hd::tl,[]) = hd::tl | merge(hd::tl,h::t) = if le(hd,h) then hd::merge(tl,h::t) else h::merge(hd::tl,t)

Page 91: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

361CS 538 Spring 2003©

fun sort [] = [] | sort([a]) = [a] | sort(a::b::rest) = let val (left,right) = split(a::b::rest) in merge(sort(left),

sort(right)) end;

fun inOrder [] = true | inOrder [a] = true | inOrder (a::b::rest) = le(a,b) andalso inOrder (b::rest);end;

362CS 538 Spring 2003©

Nowstructure IntSorting = MakeSorting(IntOrder);

creates a custom structure for sortingintegers: IntSorting.sort [3,0,~22,8];

val it = [~22,0,3,8] : elem list

To sort strings, we just define astructure containing an le definedfor strings with Order as itssignature (i.e., type) and pass it toMakeSorting :structure StrOrder:Order =

struct

type elem = string

fun le(a:string,b) = a <= b;

end;

363CS 538 Spring 2003©

structure StrSorting = MakeSorting(StrOrder);

StrSorting.sort( ["cc","abc","xyz"]);val it = ["abc","cc","xyz"] : StrOrder.elem list

StrSorting.inOrder( ["cc","abc","xyz"]);val it = false : bool

StrSorting.inOrder( [3,0,~22,8]);stdIn:593.1-593.32 Error:operator and operand don’t agree[literal]

operator domain: strOrder.elemlist operand: int list in expression:

StrSorting.inOrder (3 :: 0 ::~22 :: <exp> :: <exp>)

364CS 538 Spring 2003©

The SML Basis LibrarySML provides a wide variety of usefultypes and functions, grouped intostructures, that are included in theBasis Library.A web page fully documenting theBasis Library is linked from the MLpage that is part of the ProgrammingLanguages Links page on the CS 538home page.Many useful types, operators andfunctions are “preloaded” when youstart the SML compiler. These arelisted in the “Top-level Environment”section of the Basis Librarydocumentation.Many other useful definitions mustbe explicitly fetched from thestructures they are defined in.

Page 92: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

365CS 538 Spring 2003©

For example, the Math structurecontains a number of usefulmathematical values and operations.You may simply enteropen Math;

while will load all the definitions inMath . Doing this may load moredefinitions than you want. What’sworse, a definition loaded mayredefine a definition you currentlywant to stay active. (Recall that MLhas virtually no overloading, sofunctions with the same name indifferent structures are common.)A more selective way to access adefinition is to qualify it with thestructure’s name. HenceMath.pi;val it = 3.14159265359 : real

366CS 538 Spring 2003©

gets the value of pi defined in Math .Should you tire of repeatedlyqualifying a name, you can (ofcourse) define a local value to hold itsvalue. Thusval pi = Math.pi;val pi = 3.14159265359 : real

works fine.

367CS 538 Spring 2003©

An Overview of Structures inthe Basis Library

The Basis Library contains a widevariety of useful structures. Here is anoverview of some of the mostimportant ones.• Option

Operations for the option type.• Bool

Operations for the bool type.• Char

Operations for the char type.• String

Operations for the string type.• Byte

Operations for the byte type.• Int

Operations for the int type.

368CS 538 Spring 2003©

• IntInf

Operations for an unbounded precisioninteger type.

• Real

Operations for the real type.• Math

Various mathematical values andoperations.

• List

Operations for the list type.• ListPair

Operations on pairs of lists.• Vector

A polymorphic type for immutable(unchangeable) sequences.

• IntVector, RealVector,BoolVector, CharVector

Monomorphic types for immutablesequences.

Page 93: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

369CS 538 Spring 2003©

• Array

A polymorphic type for mutable(changeable) sequences.

• IntArray, RealArray,BoolArray, CharArray

Monomorphic types for mutablesequences.

• Array2

A polymorphic 2 dimensional mutabletype.

• IntArray2, RealArray2,BoolArray2, CharArray2

Monomorphic 2 dimensional mutabletypes.

• TextIO

Character-oriented text IO.• BinIO

Binary IO operations.• OS, Unix, Date, Time, Timer

Operating systems types and operations.

370CS 538 Spring 2003©

ML Type InferenceOne of the most novel aspects of ML isthe fact that it infers types for all userdeclarations.How does this type inference mechanismwork?Essentially, the ML compiler creates anunknown type for each declaration theuser makes. It then solves for theseunknowns using known types and a setof type inference rules. That is, for auser-defined identifier i , ML wants todetermine T(i) , the type of i .

371CS 538 Spring 2003©

The type inference rules are:1. The types of all predefined literals,

constants and functions are known inadvance. They may be looked-up andused. For example,

2 : int

true : bool

[] : 'a list

:: : 'a * 'a list -> 'a list

2. All occurrences of the same symbol(using scoping rules) have the sametype.

3. In the expressionI = J

we know T(I) = T(J) .

372CS 538 Spring 2003©

4. In a conditional(if E1 then E2 else E3)

we know thatT(E1) = bool ,T(E2) = T(E3) = T(conditional)

5. In a function call(f x)

we know that if T(f) = 'a -> 'b then T(x) = 'a and T(f x) = 'b

6. In a function definitionfun f x = expr;

if t(x) = 'a and T(expr) = 'b then T(f) = 'a -> 'b

7. In a tuple (e 1,e 2, ..., e n)

if we know that T(e i ) = 'a i 1 ≤ i ≤ n

then T(e 1,e 2, ..., e n) = 'a 1*'a 2*...*'a n

Page 94: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

373CS 538 Spring 2003©

8. In a record { a=e 1,b=e 2, ... }

if T(e i ) = 'a i 1 ≤ i ≤ n then the type of the record =

{a:'a 1, b:'a 2, ...}

9. In a list [v 1,v 2, ... v n]

if we know that T(v i ) = 'a i 1 ≤ i ≤ n

then we know that'a 1='a 2=...='a n andT([v 1,v 2, ... v n]) = 'a 1 list

374CS 538 Spring 2003©

To Solve for Types:1. Assign each untyped symbol its own

distinct type variable.2. Use rules (1) to (9) to solve for and

simplify unknown types.3. Verify that each solution “works”

(causes no type errors) throughout theprogram.

ExamplesConsiderfun fact(n)=

if n=1 then 1 else n*fact(n-1);

To begin, we’ll assign type variables:T(fact) = 'a -> 'b(fact is a function)T(n) = 'c

375CS 538 Spring 2003©

Now we begin to solve for the types'a , 'b and 'c must represent.We know (rule 5) that 'c = 'a sincen is the argument of fact .We know (rule 3) that 'c = T(1) =int since n=1 is part of the definition.We know (rule 4) that T(1) = T(ifexpression) ='b since the ifexpression is the body of fact .Thus, we have‘a = 'b ='c = int , soT(fact) = int -> int

T(n) = int

These types are correct for alloccurrences of fact and n in thedefinition.

376CS 538 Spring 2003©

A Polymorphic Function:fun leng(L) =

if L = []

then 0

else 1+len(tl L);

To begin, we know thatT([]) = 'a list andT(tl) = 'b list -> 'b list

We assign types to leng and L:T(leng) = 'c -> 'd

T(L) = 'e

Since L is the argument of leng ,'e = 'c

From the expression L=[] we know'e = 'a list

Page 95: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

377CS 538 Spring 2003©

From the fact that 0 is the result ofthe then, we know the if returns anint , so 'd = int .Thus T(leng) = 'a list -> int andT(L) = 'a list

These solutions are type correctthroughout the definition.

378CS 538 Spring 2003©

Type Inference for PatternsType inference works for patterns too.Considerfun leng [] = 0

| leng (a::b) = 1 + leng b;

We first create type variables:T(leng) = 'a -> 'b

T(a) = 'c

T(b) = 'd

From leng [] we conclude that'a = 'e list

From leng [] = 0 we conclude that'b = int

From leng (a::b) we conclude that'c ='e and 'd = 'e list

Thus we haveT(leng) = 'e list -> int

379CS 538 Spring 2003©

T(a) = 'e

T(b) = 'e list

This solution is type correctthroughout the definition.

380CS 538 Spring 2003©

Not Everything can beAutomatically Typed in ML

Let’s try to typefun f x = (x x);

We assumeT(f) = 'a -> 'b

t(x) = 'c

Now (as usual) 'a = 'c since x is theargument of f .From the call (x x) we conclude that'c must be of the form 'd -> 'e(since x is being used as a function).Moreover, 'c = 'd since x is anargument in (x x) .Thus 'c = 'd ->'e = 'c ->'e .But 'c = 'c->'e has no solution, soin ML this definition is invalid. We

Page 96: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

381CS 538 Spring 2003©

can’t pass a function to itself as anargument—the type system doesn’tallow it.In Scheme this is allowed:(define (f x) (x x))

but a call like(f f)

certainly doesn’t do anything good!

382CS 538 Spring 2003©

Type UnionsLet’s try to typefun f g = ((g 3), (g true));

Now the type of g is 'a -> 'b since gis used as a function.The call (g 3) says 'a = int and thecall (g true) says 'a = boolean .Does this mean g is polymorphic?That is, is the type of f

f : ('a->'b)->'b*'b ?NO!All functions have the type 'a -> 'bbut not all functions can be passed tof .Consider not: bool->bool .The call (not 3) is certainly illegal.

383CS 538 Spring 2003©

What we’d like in this case is a uniontype. That is, we’d like to be able totype g as (int|bool)->'b which MLdoesn’t allow.Fortunately, ML does allow typeconstructors, which are just what weneed.Givendatatype T = I of int|B of bool;

we can redefine f asfun f g = (g (I(3)), g (B(true)));val f = fn : (T -> 'a) -> 'a * 'a

384CS 538 Spring 2003©

Finally, note that in a definition likelet val f =

fn x => x (* id function*)in (f 3,f true)end;

type inference works fine:val it = (3,true) : int * bool

Here we define f in advance, so itstype is known when calls to it areseen.

Page 97: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

385CS 538 Spring 2003©

Reading Assignment• Roosta: Chapters 10 and 11

• Webber: Chapters 19, 20 and 22

386CS 538 Spring 2003©

PrologProlog presents a view ofprogramming that is very differentfrom most other programminglanguages.A famous text book is entitled“Algorithms + Data Structures =Programs”This formula represents well theconventional approach toprogramming that most programminglanguages support.In Prolog there is an alternative ruleof programming:“Algorithms = Logic + Control”This rule encompasses a non-procedural view of programming.

387CS 538 Spring 2003©

Logic (what the program is tocompute) comes first.Then control (how to implement thelogic) is considered.In Prolog we program the logic of aprogram, but the Prolog systemautomatically implements the control.Logic is essential—control is justefficiency.

388CS 538 Spring 2003©

Logic ProgrammingProlog implements logic programming.

In fact Prolog means Programmingin Logic.In Prolog programs are statements ofrules and facts.Program execution is deduction—canan answer be inferred from knownrules and facts.Prolog was developed in 1972 byKowalski and Colmerauer at theUniversity of Marseilles.

Page 98: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

389CS 538 Spring 2003©

Elementary Data Objects• In Prolog integers and atoms are the

elementary data objects.

• Integers are ordinary integer literals andvalues.

• Atoms are identifiers that begin with alower-case letter (much like symbolicvalues in Scheme).

• In Prolog data objects are called terms.

• In Prolog we define relations amongterms (integers, atoms or other terms).

• A predicate names a relation.Predicates begin with lower-case letters.

• To define a predicate, we write clausesthat define the relation.

390CS 538 Spring 2003©

• There are two kinds of program clauses,facts and rules.

• A fact is a predicate that prefixes asequence of terms, and which ends witha period (“.”).

As an example, consider the followingfacts which define “fatherOf ” and“motherOf ” relations.

fatherOf(tom,dick).

fatherOf(dick,harry).

fatherOf(jane,harry).

motherOf(tom,judy).

motherOf(dick,mary).

motherOf(jane,mary).

The symbols fatherOf and motherOfare predicates. The symbols tom ,dick , harry , judy , mary and janeare atoms.

391CS 538 Spring 2003©

Once we have entered rules and factsthat define relations, we can makequeries (ask the Prolog systemquestions).Prolog has two interactive modes thatyou can switch between.To enter definition mode (to definerules and facts) you enter[user].

You then enter facts and rules,terminating this phase with ^D (endof file).Alternatively, you can enter['filename'].

to read in rules and facts stored inthe file named filename .

392CS 538 Spring 2003©

When you start Prolog, or after youleave definitions mode, you are inquery mode.In query mode you see a prompt ofthe form| ?- or ?- (depending on the systemyou are running).In query mode, Prolog allows you toask whether a relation among terms istrue or false.Thus given our definition ofmotherOf and fatherOf relations,we can ask:| ?- fatherOf(tom,dick).yes

A “yes” response means that Prolog isable to conclude from the facts andrules it has been given that therelation queried does hold.

Page 99: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

393CS 538 Spring 2003©

| ?- fatherOf(georgeW,george).no

A “no” response to a query meansthat Prolog is unable to conclude thatthe relation holds from what it hasbeen told. The relation may actuallybe true, but Prolog may lack necessaryfacts or rules to deduce this.

394CS 538 Spring 2003©

Variables in QueriesOne of the attractive features ofProlog is the fact that variables maybe included in queries. A variablealways begins with a capital letter.When a variable is seen, Prolog triesto find a value (binding) for thevariable that will make the queriedrelation true.For example,fatherOf(X,harry).

asks Prolog to find an value for Xsuch that X’s father is harry .When we enter the query, Prologgives us a solution (if one can befound): ?- fatherOf(X,harry).

X = dick

395CS 538 Spring 2003©

If no solution can be found, it tells usso:| ?- fatherOf(Y,jane).no

Since solutions to queries need not beunique, Prolog will give us alternatesolutions if we ask for them. We doso by entering a “;” after a solution isprinted. We get a “no” when no moresolutions can be found:| ?- fatherOf(X,harry).

X = dick ;X = jane ;no

396CS 538 Spring 2003©

Variables may be placed anywhere ina query. Thus we may ask| ?- fatherOf(jane,X).

X = harry ;no

We may use more than one variable ifwe wish:| ?- fatherOf(X,Y).X = tom,

Y = dick ;X = dick,

Y = harry ;X = jane,

Y = harry ;

no(This query displays all the fatherOfrelations).

Page 100: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

397CS 538 Spring 2003©

Conjunction of GoalsMore than one relation can beincluded as the “goal” of a query. Acomma (“,”) is used as an ANDoperator to indicate a conjunction ofgoals—all must be satisfied by asolution to the query.| ?-fatherOf(jane,X),motherOf(jane,Y).

X = harry,

Y = mary ;no

A given variable may appear morethan once in a query. The same valueof the variable must be used in allplaces in which the variable appears(this is called unification).

398CS 538 Spring 2003©

For example,| ?-fatherOf(tom,X),fatherOf(X,harry).

X = dick ;no

399CS 538 Spring 2003©

Rules in PrologRules allow us to state that a relationwill hold depending on the truth(correctness) of other relations.In effect a rules says,“If I know that certain relations hold,then I also know that this relationholds.”A rule in Prolog is of the formrel 1 :- rel 2, rel 3, ... rel n.

This says rel 1 can be assumed true ifwe can establish that rel 2 and rel 3

and all relations to rel n are true.rel 1 is called the head of the rule.rel 2 to rel n form the body of therule.

400CS 538 Spring 2003©

ExampleThe following two rules define agrandMotherOf relation using themotherOf and fatherOf relations:grandMotherOf(X,GM) :-

motherOf(X,M), motherOf(M,GM).

grandMotherOf(X,GM) :-

fatherOf(X,F), motherOf(F,GM).

| ?- grandMotherOf(tom,GM).

GM = mary ;no

| ?- grandMotherOf(dick,GM).no

| ?- grandMotherOf(X,mary).

X = tom ;no

Page 101: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

401CS 538 Spring 2003©

As is the case for all programming, inall languages, you must be carefulwhen you define a rule that itcorrectly captures the idea you havein mind.Consider the following rule thatdefines a sibling relation betweentwo people:sibling(X,Y) :-motherOf(X,M), motherOf(Y,M),

fatherOf(X,F), fatherOf(Y,F).

This rule says that X and Y are siblingsif each has the same mother and thesame father.But the rule is wrong!Why?

402CS 538 Spring 2003©

Let’s give it a try:| ?- sibling(X,Y).

X = Y = tom

Darn! That’s right, you can’t be yourown sibling. So we refine the rule toforce X and Y to be distinct:sibling(X,Y) :- motherOf(X,M), motherOf(Y,M), fatherOf(X,F), fatherOf(Y,F), \+(X=Y).

In Quintus prolog “\+ ” representsnot; most other Prologs include a notrelation.

| ?- sibling(X,Y).X = dick,

Y = jane ;X = jane,

Y = dick ;no

403CS 538 Spring 2003©

Note that distinct but equivalentsolutions (like X = dick,Y = jane vs.X = jane,Y = dick ) often appear inProlog solutions. You may sometimesneed to “filter out” solutions that areeffectively redundant (perhaps byformulating stricter or more preciserules).

404CS 538 Spring 2003©

How Prolog Solves QueriesThe unique feature of Prolog is that itautomatically chooses the facts andrules needed to solve a query.But how does it make its choice?It starts by trying to solve each goalin a query, left to right (recall goalsare connected using “,” which is theand operator).For each goal it tries to match acorresponding fact or the head of acorresponding rule.

Page 102: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

405CS 538 Spring 2003©

A fact or head of rule matches a goalif:• Both use the same predicate.

• Both have the same number of termsfollowing the predicate.

• Each term in the goal and fact or rulehead match (are equal), possiblybinding a free variable to force amatch.

For example, assume we wish tomatch the following goal:x(a,B)

This can match the factx(a,b).

or the head of the rulex(Y,Z) :- Y = Z.

406CS 538 Spring 2003©

But x(a,B) can’t matchy(a,b) (wrong predicate name) orx(b,d) (first terms don’t match) orx(a,b,c) (wrong number of terms).If we succeed in matching a rule, wehave solved the goal in question; wecan go on to match any remaininggoals.If we match the head of a rule, wearen’t done—we add the body of therule to the list of goals that must besolved.Thus if we match the goal x(a,B)

with the rulex(Y,Z) :- Y = Z.

then we must solve a=B which is doneby making B equal to a.

407CS 538 Spring 2003©

BacktrackingIf we reach a point where a goal can’tbe matched, or the body of a rulecan’t be matched, we backtrack to thelast (most recent) spot where a choiceof matching a particular fact or rulewas made. We then try to match adifferent fact or rule. If this can’t bedone, we go back to the next previousplace where a choice was made andtry a different match there. We tryalternatives until we are able to solveall the goals in our query or until allpossible choices have been tried andfound to fail. If this happens, weanswer “no” the query can’t besolved.As we try to match facts and rules wetry them in their order of definition.

408CS 538 Spring 2003©

ExampleLet’s trace how| ?- grandMotherOf(tom,GM).

is solved.Recall thatgrandMotherOf(X,GM) :-

motherOf(X,M), motherOf(M,GM).

grandMotherOf(X,GM) :-

fatherOf(X,F), motherOf(F,GM).

fatherOf(tom,dick).

fatherOf(dick,harry).

fatherOf(jane,harry).

motherOf(tom,judy).

motherOf(dick,mary).

motherOf(jane,mary).

Page 103: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

409CS 538 Spring 2003©

We try the first grandMotherOf rulefirst.This forces X = tom . We have to solve motherOf(tom,M), motherOf(M,GM).

We now try to solvemotherOf(tom,M)

This forces M = judy .We then try to solvemotherOf(judy,GM)

None of the motherOf rules matchthis goal, so we backtrack. No othermotherOf rule can solvemotherOf(tom,M)

so we backtrack again and try thesecond grandMotherOf rule:

410CS 538 Spring 2003©

grandMotherOf(X,GM) :- fatherOf(X,F), motherOf(F,GM).

This matches, forcing X = tom .We have to solvefatherOf(tom,F), motherOf(F,GM).

We can match the first goal withfatherOf(tom,dick).

This forces F = dick .We then must solvemotherOf(dick,GM)

which can be matched bymotherOf(dick,mary).

We have matched all our goals, so weknow the query is true, withGM = mary .

411CS 538 Spring 2003©

List Processing in PrologProlog has a notation similar to “conscells” of Lisp and Scheme.The “.” functor (predicate name) actslike cons.Hence .(a,b) in Prolog is essentiallythe same as (a . b) in Scheme.Lists in Prolog are formed much thesame way as in Scheme and ML:[] is the empty list[1,2,3] is an abbreviation for.(1, .(2, .(3,[])))

just as(1,2,3) in Scheme is an abbreviationfor(cons 1 (cons 2 (cons 3 () )))

412CS 538 Spring 2003©

The notation [H|T] represents a listwith H matching the head of the listand T matching the rest of the list.Thus [1,2,3] ≡ [1| [2,3]] ≡[1,2| [3]] ≡ [1,2,3| [] ]

As in ML, “_” (underscore) can beused as a wildcard or “don’t care”symbol in matches.Given the fact p([1,2,3,4]).

The query | ?- p([X|Y]).

answersX = 1,

Y = [2,3,4]

Page 104: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

413CS 538 Spring 2003©

The queryp([_,_,X|Y]).

answersX = 3,

Y = [4]

414CS 538 Spring 2003©

List Operations in PrologList operations are defined using rulesand facts. The definitions are similarto those used in Scheme or ML, butthey are non-procedural.That is, you don’t given an executionorder. Instead, you give recursive rulesand non-recursive “base cases” thatcharacterize the operation you aredefining.Consider append : append([],L,L).

append([H|T1],L2,[H,T3]) :- append(T1,L2,T3).

The first fact says that an empty list(argument 1) appended to any list L(argument 2) gives L (argument 3) asits answer.

415CS 538 Spring 2003©

The rule in line 2 says that if you takea list that begins with H and has T1 asthe rest of the list and append it to alist L then the resulting appended listwill begin with H.Moreover, the rest of the resultinglist, T3, is the result of appending T1(the rest of the first list) with L2 (thesecond input list).The query | ?- append([1],[2,3],[1,2,3]).

answersYes

because with H=1, T1=[] , L2 =[2,3]and T3=[2,3] it must be the casethat append([],[2,3],[2,3]) istrue and fact (1) says that this is so.

416CS 538 Spring 2003©

Inverting Inputs and OutputsIn Prolog the division between“inputs” and “outputs” isintentionally vague. We can exploitthis. It is often possible to “invert” aquery and ask what inputs wouldcompute a given output. Few otherlanguages allow this level offlexibility. Consider the queryappend([1],X,[1,2,3]).

This asks Prolog to find a list X suchthat if we append [1] to X we willget [1,2,3] . Prolog answers

X = [2,3]

Page 105: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

417CS 538 Spring 2003©

How does it choose this answer?First Prolog tries to match the queryagainst fact (1) or rule (2).Fact (1) doesn’t match (the firstarguments differ) so we match rule(2).This gives us H=1, T1=[] , L2=X andT3 = [2,3] .We next have to solve the body ofrule (2) which is

append([],L2,[2,3]).

Fact (1) matches this, and tells usthat L2=[2,3]=X , and that’s ouranswer!

418CS 538 Spring 2003©

The Member RelationA common predicate whenmanipulating lists is a membershiptest—is a given value a member of alist?An “obvious” definition is a recursiveone similar to what we mightprogram in Scheme or ML:member(X,[X|_]).member(X,[_|Y]):- member(X,Y).

This definition states that the firstargument, X, is a member of thesecond argument (a list) if X matchesthe head of the list or if X is(recursively) a member of the rest ofthe list.

419CS 538 Spring 2003©

Note that we don’t have to “tell”Prolog that X can’t be a member of anempty list—if we don’t tell Prologthat something is true, itautomatically assumes that it must befalse.Thus saying nothing aboutmembership in an empty list is thesame as saying that membership in anempty list is impossible.Since inputs and outputs in a relationare blurred, we can use member in anunexpected way—to iterate through alist of values.

420CS 538 Spring 2003©

If we want to know if any member ofa list L satisfies a predicate p, we cansimply write:member(X,L),p(X).

There is no explicit iteration orsearching. We simply ask Prolog tofind an X such that member(X,L) istrue (X is in L) and p(X) is true.Backtracking will find the “right”value for X (if any such X exists).This is sometimes called the “guessand verify” technique.Thus we can querymember(X,[3,-3,0,10,-10]), (X > 0).

This asks for an X in the list[3,-3,0,10,-10] which is greaterthan 0.

Page 106: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

421CS 538 Spring 2003©

Prolog answersX = 3 ;X = 10 ;Note too that our “obvious”definition of member is not the onlyone possible.An alternative definition (which is farless obvious) ismember(X,L) :- append(_,[X|_],L).

This definition says X is a member ofL if I can take some list (whose valueI don’t care about) and append it to alist that begins with X (and whichends with values I don’t care about)and get a list equal to L.Said more clearly, X is a member of Lif X is anywhere in the “middle” of L.

422CS 538 Spring 2003©

Prolog solves a query involvingmember by partitioning the list L inall possible ways, and checking to seeif X ever is the head of the secondlist. Thus for member(X,[1,2,3]) , ittries the partition [] and [1,2,3](exposing 1 as a possible X), then [1]and [2,3] (exposing 2) and finally[1,2] and [3] (exposing 3).

423CS 538 Spring 2003©

Sorting AlgorithmsSorting algorithms are good examplesof Prolog’s definitional capabilities. Ina Prolog definition the “logic” of asorting algorithm is apparent,stripped of the cumbersome details ofdata structures and control structuresthat dominate algorithms in otherprogramming languages.Consider the simplest possible sortimaginable, which we’ll call the“naive sort.”At the simplest level a sorting of a listL requires just two things:• The sorting is a permutation (a

reordering) of the values in L.

• The values are “in order” (ascendingor descending).

424CS 538 Spring 2003©

We can implement this concept of asort directly in Prolog. We(a) permute an input list(b) check if it is in sorted order(c) repeat (a) & (b) until a sorting is found.

Page 107: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

425CS 538 Spring 2003©

PermutationsLet’s first look at how permutationsare defined in Prolog. In mostlanguages generating permutations isnon-trivial—you need data structuresto store the permutations you aregenerating and control structures tovisit all permutations in some order.In Prolog, permutations are definedquite concisely, though with a bit ofsubtlety:perm(X,Y) will be true if list Y is apermutation of list X.Only two definitions are needed:perm([],[]).

perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).

426CS 538 Spring 2003©

The first definition,perm([],[]).

is trivial. An empty list may only bepermuted into another empty list.The second definition is rather morecomplex:perm(L,[H|T]) :-append(V,[H|U],L), append(V,U,W), perm(W,T).

This rule says a list L may bepermuted in to a list that begins withH and ends with list T if:(1) L may be partitioned into two lists, V and [H|U] . (That is, H is somewhere in the “middle” of L).(2) Lists V and U (all of L except H) may be appended into list W.(3) List W may be permuted into T.

427CS 538 Spring 2003©

Let’s see perm in action:| ?- perm([1,2,3],X).

X = [1,2,3] ;

X = [1,3,2] ;

X = [2,1,3] ;

X = [2,3,1] ;

X = [3,1,2] ;

X = [3,2,1] ;no

We’ll trace how the first few answersare computed. Note though that allpermutations are generated, and withno apparent data structures orcontrol structures.We start with L=[1,2,3] andX=[H|T] .We first solve append(V,[H|U],L) ,which simplifies toappend(V,[H|U],[1,2,3]) .

428CS 538 Spring 2003©

One solution to this goal isV = [], H = 1, U = [2,3]

We next solve append(V,U,W) whichsimplifies to append([],[2,3],W) .The only solution for this is W=[2,3] .Finally, we solve perm(W,T) , whichsimplifies to perm([2,3],T) .One solution to this is T=[2,3] .This gives us our first solution:[H|T]=[1,2,3] .To get our next solution we backtrack.Where is the most recent place wemade a choice of how to solve a goal?It was at perm([2,3],T) . We choseT=[2,3] , but T=[3,2] is anothersolution. Using this solution, we getout next answer [H|T]=[1,3,2] .

Page 108: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

429CS 538 Spring 2003©

Let’s try one more. We backtrackagain. No more solutions are possiblefor perm([2,3],T) , so we backtrackto an earlier choice point.At append(V,[H|U],[1,2,3])another solution isV=[1], H = 2, U = [3]

Using this binding, we solveappend(V,U,W) which simplifies toappend([1],[3],W) . The solution tothis must be W=[1,3] .We then solve perm(W,T) whichsimplifies to perm([1,3],T) . Onesolution to this is T=[1,3] . Thismakes our third solution for [H|T] =[2,1,3] .You can check out the other bindingsthat lead to the last three solutions.

430CS 538 Spring 2003©

A Permutation SortNow that we know how to generatepermutations, the definition of apermutation sort is almost trivial.We define an inOrder relation thatcharacterizes our notion of when alist is properly sorted:inOrder([]).

inOrder([_]).

inOrder([A,B|T]) :- A =< B, inOrder([B|T]).

These definitions state that a null list,and a list with only one element arealways in sorted order. Longer listsare in order if the first two elementsare in proper order. (A=<B) checksthis and then the rest of the list,excluding the first element, ischecked.

431CS 538 Spring 2003©

Now our naive permutation sort isonly one line long:naiveSort(L1,L2) :- perm(L1,L2), inOrder(L2).

And the definition works too!| ?-naiveSort([1,2,3],[3,2,1]).no

?- naiveSort([3,2,1],L).

L = [1,2,3] ;no

| ?-naiveSort([7,3,88,2,1,6,77, -23,5],L).

L = [-23,1,2,3,5,6,7,77,88]

432CS 538 Spring 2003©

Though this sort works, it ishopelessly inefficient—it repeatedly“shuffles” the input until it happensto find an ordering that is sorted. Theprocess is largely undirected. Wedon’t “aim” toward a correct ordering,but just search until we get lucky.

Page 109: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

433CS 538 Spring 2003©

A Bubble SortPerhaps the best known sortingtechnique is the interchange or“bubble” sort. The idea is simple. Weexamine a list of values, looking for apair of adjacent values that are “outof order.” If we find such a pair, weswap the two values (placing them incorrect order). Otherwise, the wholelist must be in sorted order and weare done.In conventional languages we need alot of code to search for out-of-orderpairs, and to systematically reorderthem. In Prolog, the whole sort maybe defined in a few lines:

434CS 538 Spring 2003©

bubbleSort(L,L) :- inOrder(L).

bubbleSort(L1,L2) :- append(X,[A,B|Y],L1), A > B, append(X,[B,A|Y],T), bubbleSort(T,L2).

The first line says that if L is alreadyin sorted order, we are done.The second line is a bit more complex.It defines what it means for a list L2to be a sorting for list L1 , using ourinsight that we should swap out-of-order neighbors. We first partition listL1 into two lists, X and [A,B|Y] . This“exposes” two adjacent values in L, Aand B. Next we verify that A and B areout-of-order (A>B) . Next, inappend(X,[B,A|Y],T) , wedetermine that list T is just our inputL, with A and B swapped into Bfollowed by A.

435CS 538 Spring 2003©

Finally, we verify thatbubbleSort(T,L2) holds. That is, Tmay be bubble-sorted into L2 .This approach is rather more directedthan our permutation sort—we lookfor an out-of-order pair of values,swap them, and then sort the“improved” list. Eventually there willbe no more out-of-order pairs, thelist will be in sorted order, and we willbe done.

436CS 538 Spring 2003©

Merge SortAnother popular sort in the “mergesort” that we have already seen inScheme and ML. The idea here is tofirst split a list of length L into twosublists of length L/2. Each of thesetwo lists is recursively sorted. Finally,the two sorted sublists are mergedtogether to form a complete sortedlist.The bubble sort can take timeproportional to n2 to sort n elements(as many as n2/2 swaps may beneeded). The merge sort does better—it takes time proportional to n log 2 nto sort n elements (a list of size n canonly be split in half log 2 n times).

Page 110: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

437CS 538 Spring 2003©

We first need Prolog rules on how tosplit a list into two equal halves:split([],[],[]).split([A],[A],[]).split([A,B|T],[A|P1],[B|P2]) :- split(T,P1,P2).

The first two lines characterize trivialsplits. The third rule distributes one ofthe first two elements to each of thetwo sublists, and then recursivelysplits the rest of the list.

438CS 538 Spring 2003©

We also need rules that characterizehow to merge two sorted sublists intoa complete sorted list:merge([],L,L).merge(L,[],L).merge([A|T1],[B|T2],[A|L2]) :- A =< B, merge(T1,[B|T2],L2).merge([A|T1],[B|T2],[B|L2]) :- A > B, merge([A|T1],T2,L2).

The first 2 lines handle merging nulllists. The third line handles the casewhere the head of the first sublist is ≤the head of the second sublist; thefinal rule handles the case where thehead of the second sublist is smaller.

439CS 538 Spring 2003©

With the above definitions, a mergesort requires only three lines:mergeSort([],[]).

mergeSort([A],[A]).mergeSort(L1,L2) :- split(L1,P1,P2), mergeSort(P1,S1),

mergeSort(P2,S2),merge(S1,S2,L2).

The first two lines handle the trivialcases of lists of length 0 or 1. The lastline contains the full “logic” of amerge sort: split the input list, L intotwo half-sized lists P1 and P2. Thenmerge sort P1 into S1 and P2 into S2.Finally, merge S1 and S2 into a sortedlist L2 . That’s it!

440CS 538 Spring 2003©

Quick SortThe merge sort partitions its input listrather blindly, alternating valuesbetween the two lists. What if wepartitioned the input list based onvalues rather than positions?The quick sort does this. It selects a“pivot” value (the head of the inputlist) and divides the input into twosublists based on whether the valuesin the list are less than the pivot orgreater than or equal to the pivot.Next the two sublists are recursivelysorted. But now, after sorting, nomerge phase is needed. Rather, thetwo sorted sublists can simply beappended, since we know all values inthe first list are less than all values inthe second list.

Page 111: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

441CS 538 Spring 2003©

We need a Prolog relation thatcharacterizes how we will do ourpartitioning. We we definepartition(E,L1,L2,L3) to be trueif L1 can be partitioned into L2 andL3 using E as the pivot element. Thenecessary rules are:partition(E,[],[],[]).partition(E,[A|T1],[A|T2],L3) :- A<E, partition(E,T1,T2,L3).partition(E,[A|T1],L2,[A|T3]) :- A>=E, partition(E,T1,L2,T3)

The first line defines a trivial partitionof a null list. The second line handlesthe case in which the first element ofthe list to be partitioned is less thanthe pivot, while the final line handlesthe case in which the list head isgreater than or equal to the pivot.

442CS 538 Spring 2003©

With our notion of partitioningdefined, the quicksort itself requiresonly 2 lines:qsort([],[]).qsort([A|T],L) :-

partition(A,T,L1,L2),qsort(L1,S1),qsort(L2,S2),append(S1,[A|S2],L).

The first line defines a trivial sort ofan empty list.The second line says to sort a list thatbegins with A and ends with list T, wepartition T into sublists L1 and L2 ,based on A. Then we recursively quicksort L1 into S1 and L2 into S2.Finally we append S1 to [A|S2](A must be > all values in S1 and Amust be ≤ all values in S2). The resultis L, a sorting of [A|T] .

443CS 538 Spring 2003©

Arithmetic in PrologThe = predicate can be used to testbound variables for equality (actually,identity).If one or both of =’s arguments arefree variables, = forces a binding oran equality constraint.Thus| ?- 1=2.no

| ?- X=2.

X = 2

| ?- Y=X.

Y = X = _10751

| ?- X=Y, X=joe.

X = Y = joe

444CS 538 Spring 2003©

Arithmetic Terms are SymbolicEvaluation of an arithmetic term intoa numeric value must be forced.That is, 1+2 is an infix representationof the relation +(1,2) . This term isnot an integer!Therefore| ?- 1+2=3.no

To force arithmetic evaluation, we usethe infix predicate is .The right-hand side of is must be allground terms (literals or variables thatare already bound). No free(unbound) variables are allowed.

Page 112: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

445CS 538 Spring 2003©

Hence|?- 2 is 1+1.yes

| ?- X is 3*4.X = 12

| ?- Y is Z+1.! Instantiation error in argument2 of is/2! goal: _10712 is _10715+1

The requirement that the right-handside of an is relation be ground isessentially procedural. It exists toavoid having to invert complexequations. Consider,(0 is (I**N)+(J**N)-K**N)), N>2.

446CS 538 Spring 2003©

Counting in PrologRules that involve counting often usethe is predicate to evaluate anumeric value.Consider the relation len(L,N) thatis true if the length of list L is N.len([],0).

len([_|T],N) :- len(T,M), N is M+1.

| ?- len([1,2,3],X).

X = 3

| ?- len(Y,2).

Y = [_10903,_10905]

The symbols _10903 and _10905 are“internal variables” created as neededwhen a particular value is not forcedin a solution.

447CS 538 Spring 2003©

Debugging PrologCare is required in developing andtesting Prolog programs because thelanguage is untyped; undeclaredpredicates or relations are simplytreated as false.Thus in a definition like adj([A,B|_]) :- A=B.

adj([_,B|T]) :- adk([B|T]).

| ?- adj([1,2,2]).no

(Quintus does warn when anundefined relation is referenced, butmany other Prologs don’t).

448CS 538 Spring 2003©

Similarly, givenmember(A,[A|_]).

member(A,[_|T]) :- member(A,[T]).

| ?- member(2,[1,2]).

Infinite recursion! (Why?)

If you’re not sure what is going on,Prolog’s trace feature is very handy.The commandtrace.

turns on tracing. (notrace turnstracing off).Hence| ?- trace.yes

[trace]

| ?- member(2,[1,2]).

Page 113: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

449CS 538 Spring 2003©

(1) 0 Call: member(2,[1,2]) ?

(1) 1 Head [1->2]:member(2,[1,2]) ?

(1) 1 Head [2]:member(2,[1,2]) ?

(2) 1 Call: member(2,[[2]]) ?

(2) 2 Head [1->2]:member(2,[[2]]) ?

(2) 2 Head [2]:member(2,[[2]]) ?

(3) 2 Call: member(2,[[]]) ?

(3) 3 Head [1->2]:member(2,[[]]) ?

(3) 3 Head [2]: member(2,[[]])?

(4) 3 Call: member(2,[[]]) ?

(4) 4 Head [1->2]:member(2,[[]]) ?

(4) 4 Head [2]: member(2,[[]])?

(5) 4 Call: member(2,[[]]) ?

450CS 538 Spring 2003©

Termination Issues in PrologSearching infinite domains (likeintegers) can lead to non-termination, with Prolog trying everyvalue.Considerodd(1).

odd(N) :- odd(M), N is M+2.

| ?- odd(X).

X = 1 ;

X = 3 ;

X = 5 ;X = 7

451CS 538 Spring 2003©

A query | ?- odd(X), X=2.

going into an infinite search,generating each and every oddinteger and finding none is equal to2!The obvious alternative,odd(2) (which is equivalent toX=2, odd(X) ) also does an infinite,but fruitless search.We’ll soon learn that Prolog doeshave a mechanism to “cut off”fruitless searches.

452CS 538 Spring 2003©

Definition Order can MatterIdeally, the order of definition offacts and rules should not matter.But,in practice definition order canmatter. A good general guideline is todefine facts before rules. To see why,consider a very complete database ofmotherOf relations that goes back asfar asmotherOf(cain,eve).

Now we defineisMortal(X) :- isMortal(Y), motherOf(X,Y).

isMortal(eve).

Page 114: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

453CS 538 Spring 2003©

These definitions state that the firstwoman was mortal, and allindividuals descended from her arealso mortal.But when we try as trivial a query as| ?- isMortal(eve).

we go into an infinite search!Why?Let’s trace what Prolog does when itsees| ?- isMortal(eve).

It matches with the first definitioninvolving isMortal , which isisMortal(X) :- isMortal(Y), motherOf(X,Y).

It sets X=eve and tries to solveisMortal(Y), motherOf(eve,Y).

It will then expand isMortal(Y) into

454CS 538 Spring 2003©

isMortal(Z), motherOf(Y,Z).

An infinite expansion ensues.The solution is simple—place the“base case” fact that terminatesrecursion first.If we useisMortal(eve).

isMortal(X) :- isMortal(Y), motherOf(X,Y).yes

| ?- isMortal(eve).

yes

But now another problem appears!If we ask| ?- isMortal(clarkKent).

we go into another infinite search!Why?

455CS 538 Spring 2003©

The problem is that Clark Kent is fromthe planet Krypton, and hence won’tappear in our motherOf database.Let’s trace the query.It doesn’t match isMortal(eve) .We next tryisMortal(clarkKent) :- isMortal(Y), motherOf(clarkKent,Y).

We try Y=eve , but eve isn’t Clark’smother. So we recurse, getting:isMortal(Z), motherOf(Y,Z),motherOf(clarkKent,Y).

But eve isn’t Clark’s grandmothereither! So we keep going further back,trying to find a chain of descendentsthat leads from eve to clarkKent .No such chain exists, and there is no

456CS 538 Spring 2003©

limit to how long a chain Prolog willtry.There is a solution though!We simply rewrite our recursivedefinition to be isMortal(X) :- motherOf(X,Y),isMortal(Y).

This is logically the same, but now wework from the individual X backtoward eve , rather than from evetoward X. Since we have nomotherOf relation involvingclarkKent , we immediately stop oursearch and answer no!

Page 115: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

457CS 538 Spring 2003©

Extra-logical Aspects ofProlog

To make a Prolog program moreefficient, or to represent negativeinformation, Prolog needs featuresthat have a procedural flavor. Theseconstructs are called “extra-logical”because they go beyond Prolog’s coreof logic-based inference.

458CS 538 Spring 2003©

The CutThe most commonly used extra-logical feature of Prolog is the “cutsymbol,” “!”A ! in a goal, fact or rule “cuts off”backtracking.In particular, once a ! is reached (andautomatically matched), we may notbacktrack across it. The rule we’veselected and the bindings we’vealready selected are “locked in” or“frozen.”For example, givenx(A) :- y(A,B), z(B), ! , v(B,C).

once the ! is hit we can’t backtrackto resatisfy y(A,B) or z(B) in someother way. We are locked into this

459CS 538 Spring 2003©

rule, with the bindings of A and Balready in place.We can backtrack to try varioussolutions to v(B,C) .It is sometimes useful to have several! ’s in a rule. This allows us to find apartial solution, lock it in, find afurther solution, then lock it in, etc.For example, in a rulea(X) - b(X), !, c(X,Y), ! , d(Y).

we first try to satisfy b(X) , perhapstrying several facts or rules thatdefine the b relation. Once we have asolution to b(X) , we lock it in, alongwith the binding for X.Then we try to satisfy c(X,Y) , usingthe fixed binding for X, but perhapstrying several bindings for Y untilc(X,Y) is satisfied.

460CS 538 Spring 2003©

We then lock in this match usinganother ! .Finally we check if d(Y) can besatisfied with the binding of Y alreadyselected and locked in.

Page 116: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

461CS 538 Spring 2003©

When are Cuts Needed?A cut can be useful in improvingefficiency, by forcing Prolog to avoiduseless or redundant searches.Consider a query likemember(X,list1),

member(X,list2), isPrime(X).

This asks Prolog to find an X that is inlist1 and also in list2 and also isprime.X will be bound, in sequence, to eachvalue in list1 . We then check if X isalso in list2 , and then check if X isprime.Assume we find X=8 is in list1 andlist2 . isPrime(8) fails (of course).We backtrack to member(X,list2)and try to resatisfy it with the samevalue of X.

462CS 538 Spring 2003©

But clearly there is never any point intrying to resatisfy member(X,list2) .Once we know a value of X is inlist2 , we test it using isPrime(X) .If it fails, we want to go right back tomember(X,list1) and get adifferent X.To create a version of member thatnever backtracks once it has beensatisfied we can use ! .We definemember1(X,[X|_]) :- !.member1(X,[_|Y]) :- member1(X,Y).

Our query is nowmember(X,list1), member1(X,list2), isPrime(X).

(Why isn’t member1 used in bothterms?)

463CS 538 Spring 2003©

Expressing NegativeInformation

Sometimes it is useful to state rulesabout what can’t be true. This allowsus to avoid long and fruitlesssearches.fail is a goal that always fails. It canbe used to represent goals or resultsthat can never be true.Assume we want to optimize ourgrandMotherOf rules by stating thata male can never be anyone’sgrandmother (and hence a completesearch of all motherOf andfatherOf relations is useless).A rule to do this isgrandMotherOf(X,GM) :- male(GM), fail.

464CS 538 Spring 2003©

This rule doesn’t do quite what wehope it will!Why?The standard approach in Prolog is totry other rules if the current rule fails.Hence we need some way to “cut off”any further backtracking once thisnegative rule is found to beapplicable.This can be done using grandMotherOf(X,GM) :- male(GM),!, fail.

Page 117: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

465CS 538 Spring 2003©

Other Extra-LogicalOperators

• assert and retract

These operators allow a Prologprogram to add new rules duringexecution and (perhaps) later removethem. This allows programs to learnas they execute.• findall

Called as findall(X,goal,List)where X is a variable in goal . Allpossible solutions for X that satisfygoal are found and placed in List .For example,findall(X,(append(_,[X|_],[-1,2,-3,4]),(X<0)), L).

L = [-1,-3]

466CS 538 Spring 2003©

• var and nonvar

var(X) tests whether X is unbound(free).nonvar(Y) tests whether Y is bound(no longer free).These two operators are useful intailoring rules to particularcombinations of bound and unboundvariables.For example, the rulegrandMotherOf(X,GM) :- male(GM),!, fail.

might backfire if GMis not yet bound.We could set GM to a person forwhom male(GM) is true, then failbecause we don’t want grandmotherswho are male!

467CS 538 Spring 2003©

To remedy this problem. we use therule only when GM is bound. Our rulebecomesgrandMotherOf(X,GM) :- nonvar(GM), male(GM),!, fail.

468CS 538 Spring 2003©

An Example of Extra-LogicalProgramming

Factorial is a very common exampleprogram. It’s well known, and easy tocode in most languages.In Prolog the “obvious” solution is:fact(N,1) :- N =< 1.

fact(N,F) :- N > 1, M is N-1, fact(M,G), F is N*G.

This definition is certainly correct. Itmimics the usual recursive solution.But,in Prolog “inputs” and “outputs” areless distinct than in most languages.In fact, we can envision 4 differentcombinations of inputs and outputs,based on what is fixed (and thus an

Page 118: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

469CS 538 Spring 2003©

input) and what is free (and hence isto be computed):

1. N and F are both ground (fixed). Wesimply must decide if F=N!

2. N is ground and F is free. This ishow fact is usually used. We mustcompute an F such that F=N!

3. F is fixed and N is free. This is anuncommon usage. We must find anN such that F=N!, or determine thatno such N is possible.

4. Both N and F are free. We generate,in sequence, pairs of N and F valuessuch that F=N!

470CS 538 Spring 2003©

Our solution works for combinations1 and 2 (where N is fixed), but notcombinations 3 and 4. (The problemis that N =< 1 and N > 1 can’t besatisfied when N is free).We’ll need to use nonvar and ! toform a solution that works for all 4combinations of inputs.We first handle the case where N isground:fact(1,1).fact(N,1) :- nonvar(N), N =< 1, ! .fact(N,F) :- nonvar(N) , N > 1, !,M is N-1, fact(M,G), F is N*G, ! .

The first rule handles the base case ofN=1.The second rule handles the case ofN<1.

471CS 538 Spring 2003©

The third rule handles the case ofN >1 . The value of F is computedrecursively. The first ! in each ofthese rules forces that rule to be theonly one used for the values of N thatmatch. Moreover, the second ! in thethird rule states that after F iscomputed, further backtracking isuseless; there is only one F value forany given N value.To handle the case where F is boundand N is free, we usefact(N,F) :- nonvar(F), !, fact(M,G), N is M+1, F2 is N*G, F =< F2, !, F=F2.

In this rule we generate N, F2 pairsuntil F2 >= F . Then we check ifF=F2. If this is so, we have the N wewant. Otherwise, no such N can existand we fail (and answer no).

472CS 538 Spring 2003©

For the case where both N and F arefree we use:fact(N,F) :- fact(M,G), N is M+1, F is N*G.

This systematically generates N, Fpairs, starting with N=2, F=2 and thenrecursively building successor values(N=3, F=6, then N=4, F=24 , etc.)

Page 119: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

473CS 538 Spring 2003©

Parallelism in PrologOne reason that Prolog is of interestto computer scientists is that itssearch mechanism lends itself toparallel evaluation.In fact, it supports two differentkinds of parallelism:• AND Parallelism

• OR Parallelism

474CS 538 Spring 2003©

And ParallelismWhen we have a goal that containssubgoals connected by the “,” (And)operator, we may be able to utilize“and parallelism.”Rather than solve subgoals insequence, we may be able to solvethem in parallel if bindings can beproperly propagated.Thus ina(X), b(X,Y), c(X,Z), d(Y,Z).

we may be able to first solve a(X) ,binding X, then solve b(X,Y) andc(X,Z) in parallel, binding Y and Z,then finally solve d(Y,Z) .

475CS 538 Spring 2003©

An example of this sort of andparallelism ismember(X,list1), member1(X,list2), isPrime(X).

Here we can let member(X,list1)select an X value, then testmember1(X,list2) and isPrime(X)in parallel. If one or the other fails,we just select another X from list1and retest member1(X,list2) andisPrime(X) in parallel.

476CS 538 Spring 2003©

OR ParallelismWhen we match a goal we almostalways have a choice of several rulesor facts that may be applicable.Rather than try them in sequence, wecan try several matches of differentfacts or rules in parallel. This is “orparallelism.”Thus given a(X) :- b(X).

a(Y) :- c(Y).

when we try to solvea(10).

we can simultaneously check bothb(10) and c(10) .

Page 120: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

477CS 538 Spring 2003©

Recall our definition ofmember(X,L) :- append(P,[X|S],L).

where append is defined asappend([],L,L).

append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).

Assume we have the query| ? member(2,[1,2,3]).

This immediately simplifies toappend(P,[2|S],[1,2,3]).

Now there are two appenddefinitions we can try in parallel:(1) match append(P,[2|S],[1,2,3])

with append([],L,L) . This requiresthat [2|S] = [1,2,3] , which mustfail.(2) match append(P,[2|S],[1,2,3])

with append([X|L1],L2,[X,L3]) .

478CS 538 Spring 2003©

This requires that P=[X|L1] ,[2|S]=L2 , [1,2,3]=[X,L3] .Simplifying, we require that X=1,P=[1|L1] , L3=[2,3] .Moreover we must solveappend(L1,L2,L3) which simplifiesto append(L1,[2|S],[2,3]) .We can match this call to append intwo different ways, so or parallelismcan be used again.When we try matchingappend(L1,[2|S],[2,3]) againstappend([],L,L) we get[2|S]=[2,3] , which is satisfiable if Sis bound to [3] . We therefore signalback that the query is true.

479CS 538 Spring 2003©

Speculative ParallelismProlog also lends itself nicely tospeculative parallelism. In this form ofparallelism, we “guess” or speculatethat some computation may beneeded in the future and start it early.This speculative computation canoften be done in parallel with themain (non-speculative) computation.Recall our example ofmember(X,list1), member1(X,list2), isPrime(X).

After member(X,list1) hasgenerated a preliminary solution forX, it is tested (perhaps in parallel) bymember1(X,list2) andisPrime(X) .But this value of X may be rejected byone or both of these tests. If it is,

480CS 538 Spring 2003©

we’ll ask member(X,list1) to find anew binding for X. If we wish, thisnext binding can be generatedspeculatively, while the current valueof X is being tested. In this way if thecurrent value of X is rejected, we’llhave a new value ready to try (orknow that no other binding of X ispossible).If the current value of X is accepted,the extra speculative work we did isignored. It wasn’t needed, but wasuseful insurance in case further Xbindings were needed.

Page 121: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

481CS 538 Spring 2003©

Reading Assignment• Java for C++ Programmers

(linked from class web page)

• Roosta: Section 9.3

• Webber: Chapters 13, 15 and 17

482CS 538 Spring 2003©

Java & Object-OrientedProgramming

Java is a fairly new and very popularprogramming language designed tosupport secure, platform-independentprogramming.It is a good alternative to C or C++,trading a bit of efficiency for easierprogramming, debugging andmaintenance.Java is routinely interpreted (at thebyte-code level), making itsignificantly slower than compiled Cor C++. However true Java compilersexist, and are becoming more wide-spread. (IBM’s Jalapeno project is agood example). When compiled,Java’s execution speed is close to thatof C or C++.

483CS 538 Spring 2003©

Basic NotionsIn Java data is either primitive or anobject (an instance of some class).All code is written inside classes, soJava programming consists of writingclasses.Primitive data types are quite close tothose of C or C++:boolean (not a numeric type)char (Unicode, 16 bits)byte

short

int

long (64 bits)float

double

484CS 538 Spring 2003©

Objects• All Java objects are instances of classes.

• All objects are heap-allocated, withautomatic garbage collection.

• A reference to an object, in a variable,parameter or another object, is actually apointer to some object allocated withinthe heap.

• No explicit pointer manipulationoperations (like * or -> or ++) areneeded or allowed.

• Example:class Point {int x,y;}

Point data = new Point();

Page 122: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

485CS 538 Spring 2003©

• Declaring an object reference (like classPoint ) does not automatically allocatespace for an object. The reference isinitialized to null unless an explicitinitializer is included.

• Fields are accessed just as they are in C:data.x references field x in objectdata .

• Object references are automaticallychecked for validity (null or non-null).Hencedata.x = 0;

forces a run-time exception if datacontains null rather than a valid objectreference.

486CS 538 Spring 2003©

• Java makes it impossible for an objectreference to access an illegal address. Areference is either null or a pointer to avalid, type-correct object in the heap.(This makes Java programs far moresecure and reliable than C or C++programs).

487CS 538 Spring 2003©

Class MembersClasses contain members. Classmembers are either fields (data) ormethods (functions).Example: class Point {

int x,y;

void clear() {x=0; y=0;} }

Point d = new Point():

d.clear();

A special method is a constructor.A constructor has no result type. It isused only to define the initializationof an object after the object has beencreated.

488CS 538 Spring 2003©

Constructors may be overloaded.

class Point {

int x,y;

Point() {x=0; y=0;}

Point(int xin, int yin) {

x = xin; y = yin; }}

Page 123: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

489CS 538 Spring 2003©

Static MembersClass members may be static.A static member is allocated onlyonce—for all instances of the class.Ordinary members (called instancemembers) apply only to a particularclass instance (i.e., only one objectcreated from the class definition).class Point {

int x,y; static int howMany = 0;

Point() {x=0; y=0; howMany++;}

static void reset() {

howMany = 0; }}

490CS 538 Spring 2003©

Static member functions (methods)may not access non-static data.(Why?)Static members are accessed using aclass name rather than the name ofan object reference.For example, Point.reset();

491CS 538 Spring 2003©

Visibility of Class MembersClass members may be declared aspublic, private or protected.Public members may be accessed fromoutside a class.Private members of a class may beaccessed only from with the classitself.Protected members may be accessedonly from with the class itself or fromwithin one of its subclasses.Members nor marked public, privateor protected are shared at thepackage level—similar to C++’s friendmechanism.

492CS 538 Spring 2003©

Example: class Customer {

int id;

private int pinCode;

}

Customer me = new Customer();

me.id = 1234; //OK

me.pinCode = 7777;//Compile-time error

In a class, a special method, main ,declared as static public void main(String[] args)

is automatically executed when aclass is run.main is very useful as a “test driver”for auxiliary and library classes.

Page 124: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

493CS 538 Spring 2003©

Final MembersA field may be declared final makingit effectively a constant.class Point {

int x,y;

static final Point origin= new Point(0,0);

Point(int xin, int yin) {

x = xin; y = yin; }}

Final fields may be used to createconstants within a class:class Card { final static int Clubs = 1; final static int Diamonds = 2; final static int Hearts = 3; final static int Spades = 4; int suit = Spades;}

494CS 538 Spring 2003©

Inside a class suit names are availablefor use without qualification. E.g.,int suit = Spades;

Outside a class, the field names mustbe qualified using the class name:Card c = new Card();

c.suit = Card.Clubs;

Methods may also be marked as final.This forbids redeclaration in asubclass, allowing a more efficientimplementation. Security may also beimproved if a key method is known tobe unchangeable.

495CS 538 Spring 2003©

Java ArraysIn Java, arrays are implemented as aspecial kind of class. Arrays ofprimitive types are implemented as anobject that contains a block of valueswithin it. Arrays of objects areimplemented as an object thatcontains a block of object referenceswithin it. Allocating an array ofobjects does not allocate the objectsthemselves. Hence within an array ofobjects, some positions may referenceactual objects while other maycontain null (this can beadvantageous) if objects are large.Multi-dimensional arrays are arraysof arrays. Arrays within an array neednot all have the same size.Hence we may see

496CS 538 Spring 2003©

int[][] TwoDim = new int[3][];

TwoDim[0] = new int[1];

TwoDim[1] = new int[2];

TwoDim[2] = new int[3];

The size of an array is part of itsvalue; not its type.Thusint [] A = new int[10];

int [] B = new int[5];

A = B;

is valid.Pascal showed that making an array’ssize part of its type is undesirable.(Why?)Still, forcing an array to have a fixedsize can be necessary (e.g., an arrayindexed by months). (How do wesimulate a fixed-size array?).

Page 125: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

497CS 538 Spring 2003©

Subclassing in JavaWhen a new class is defined in termsof an existing class, the new classextends the existing class. The newclass inherits all public and protectedmembers of its parent (or base) class.The new class may add new methodsor fields. It may also redefineinherited methods or fields.class Point {

int x,y; Point(int xin, int yin) { x = xin; y = yin; } static float dist( Point P1, Point P2) { return (float) Math.sqrt( (P1.x-P2.x)*(P1.x-P2.x)+

(P1.y-P2.y)*(P1.y-P2.y)); }}

498CS 538 Spring 2003©

class Point3 extends Point {

int z; Point3(int xin, int yin, int zin) { super(xin,yin); z=zin; } static float dist( Point3 P1, Point3 P2) { float d=Point.dist(P1,P2); return (float) Math.sqrt( (P1.z-P2.z)*(P1.z-P2.z)+

d*d); }}

Note that although Point3 redefinesdist , the old definition of dist isstill available by using the parentclass as a qualifier (Point.dist ).The same is true for fields that arehidden when a field in a parent isredeclared.

499CS 538 Spring 2003©

Non-static methods are automaticallyvirtual: a redefined method isautomatically used in all inheritedmethods including those defined inparent classes that think they areusing an earlier definition of theclass.Example: class C {

void DoIt()(PrintIt();} void PrintIt() {println("C rules!");} } class D extends C { void PrintIt() {println("D rules!");} void TestIt() {DoIt();} } D dvar = new D(); dvar.TestIt();

D rules! is printed.

500CS 538 Spring 2003©

Static methods in Java are not virtual(this can make them easier toimplement efficiently).

Page 126: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

501CS 538 Spring 2003©

Abstract Classes and MethodsSometimes a Java class is not meantto be used by itself because it isintentionally incomplete.Rather, the class is meant to bestarting point for the creation (viasubclassing) of more completeclasses.Such classes are abstract.Example:abstract class Shape {

Point location;

}

class Circle extends Shape {

float radius;

}

502CS 538 Spring 2003©

Methods can also be made abstract toindicate that their actual definitionwill appear in subclasses:abstract class Shape { Point location; abstract float area();}class Circle extends Shape { float radius; float area(){ return Math.pi*radius*radius; }}

503CS 538 Spring 2003©

Subtyping and InheritanceWe can use a subtyping mechanism,as found in C++ or Java, for twodifferent purposes:• We may wish to inherit the actual

implementations of classes andmembers to use as the basis of amore complete or extended class.To inherit an implementation, we saya given class “extends” an existingclass:class Derived extends Base { ... };

Class Derived contains all of themembers of Base plus any others itcares to add.

504CS 538 Spring 2003©

• We may wish to inherit an interface—a set of method names and valuesthat will be available for use.To inherit (or claim) an interface, weuse a Java interface definition.An interface doesn’t implementanything; rather, it gives a name to aset of operations or values that maybe available within one or moreclasses.

Page 127: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

505CS 538 Spring 2003©

Why are Interfaces Important?Many classes, although very different,share a common subset of values oroperations. We may be willing to useany such class as long as onlyinterface values or operations areused.For example, many objects can beordered (or at least partially-ordered)using a “less than” operation.If we always implement less than thesame way, for example,boolean lessThan(Object o1,

Object o2);

then we can create an interface thatadmits all classes that know aboutthe lessThan function:

506CS 538 Spring 2003©

interface Compare {

boolean lessThan(Object o1, Object o2);

}

Now different classes can eachimplement the Compare interface,proclaiming to the world that theyknow how to compare objects of theclass they define:class IntCompare implements Compare { public boolean lessThan(Object i1, Object i2){ return ((Integer)i1).intValue() < ((Integer)i2).intValue();}}class StringCompare implements Compare { public boolean lessThan(Object i1, Object i2){ return((String)i1).compareTo((String)i2)<0;}}

507CS 538 Spring 2003©

The advantage of using interfaces isthat we can now define a method orclass that only depends on the giveninterface, and which will accept anytype that implements that interface.class PrintCompare { public static void printAns( Object v1, Object v2, Compare c){ System.out.println( v1.toString() + " < " +

v2.toString() + " is " + new Boolean(c.lessThan(v1,v2)) .toString());} }class Test { public static void main(String args[]){ Integer i1 = new Integer(2); Integer i2 = new Integer(1); PrintCompare.printAns( i1,i2,new IntCompare()); String s2 = "abcdef"; String s1 = "xyzaa"; PrintCompare.printAns( s1,s2,new StringCompare());}}

508CS 538 Spring 2003©

Since classes may have many methodsand modes of use or operation, agiven class may implement manydifferent interfaces. For example,many classes support the Clonableinterface, which states that objects ofthe class may be duplicated (cloned).

Page 128: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

509CS 538 Spring 2003©

Multiple InheritanceWe have seen that a class may bederived from a given parent class. It issometimes useful to allow a class tobe derived from more than oneparent, inheriting members of allparents. This is multiple inheritance; itis allowed by C++ and Python, butnot by Java or C#.The basic idea is that sometimes wewant a “composite” object formedfrom more than one source. Hence aComputer object can be viewed asboth a PhysicalObject ( withheight, weight, color, cost, etc.) andalso a CPUImplementation (withmemory size, processor design,processor speed, I/O ports, etc.)

510CS 538 Spring 2003©

Using multiple inheritance we mergeaspects of a PhysicalObject and aCPUImplementation , and perhapsadd additional data:class PhysicalObject { float height, width, weight; Color outsideColor; ... }class CPUImplementation { CPUClass CPUKind; int memorySize, CPUSpeed; ...}class Computer: PhysicalObject, CPUImplementation { String myURL; ...}

The advantages of multipleinheritance are obvious—you canbuild a class from many sourcesrather than just one.

511CS 538 Spring 2003©

There are problems though:• If the same name appears in more

than one parent, which is used? Forexample, if both parents contain a“copyright” field, which do you get?C++ forbids access to fields commonto several parents, though accidentalclashes of member names arecertainly possible. Python relies onorder of specification of the parents(which can be somewhat arbitrary).

• Access to fields and methods can beless efficient. A method in a parentclass can’t know how fields in derivedclass will be allocated when multipleparents may exist. Hence some formof indirection may be needed.For example, in classPhysicalObject , we may believe

512CS 538 Spring 2003©

that height is the first fieldallocated, while inCPUImplementation we maybelieve that CPUKind is allocatedfirst. But in class Computer , whichcontains both height and CPUKind ,both fields can’t come first.

Page 129: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

513CS 538 Spring 2003©

Exceptions in JavaJava provides a fairly elaborateexception handling mechanism basedon the throw-catch model.All exceptions are objects, required tobe a subclass of Throwable .Class Throwable has two subclasses,Exception and Error . ClassException has a subclassRuntimeException .Exceptions may be explicitly thrown(using a throw statement) or theymay be implicitly thrown as the resultof a run-time error.For example, anArithmeticException is thrown forcertain run-time arithmetic errors,like division by zero.

514CS 538 Spring 2003©

Unlike other languages, Java dividesexceptions into two general classes:checked and unchecked.A checked exception must either becaught (using a try-catch block) orpropagated (by marking a method asthrowing the exception).This means that checked exceptionscannot be ignored—you must beprepared to catch them or you must“advertise” to your callers that youmay throw an exception back tothem.Unchecked exceptions need not becaught or marked as potentiallythrown. This makes exceptionhandling for such exceptionsoptional. Unchecked exceptions aretypically those that might occur so

515CS 538 Spring 2003©

often (like NullPointerExceptionor ArithmeticException ) thatforced checks could unnecessarilyclutter a program without significantbenefit.How are checked and uncheckedexceptions distinguished?• Any exception that is a member (or

subclass) of Error orRuntimeException is unchecked.

• All other exceptions must be checked.Exceptions are propagateddynamically:• When an exception is thrown

(explicitly or implicitly) theinnermost try-catch block that can“catch” the exception is selected, and

516CS 538 Spring 2003©

the catch block that matches theexception is executed.

• A catch block “catches” a givenexception if the class of theexception is the same as the classused in the catch. An exception thatis a subclass of the catch’s exceptionclass will also be caught.Thus an catch that handles classThrowable catches all exceptions.

• If no catch can handle the exceptionin the current method, a return to themethod’s caller is forced, and theexception is rethrown from the pointof call.

• This process is repeated until a catchthat can handle the exception isfound or until we force a return fromthe main method.

Page 130: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

517CS 538 Spring 2003©

• If a return from the main method isforced, no handler exists. A run-timeerror message is printed (“Uncaughtexception”) and execution isterminated.

• One of the limitations of Java’sexception mechanism (and similarmechanisms found in otherlanguages) is that there is no “retry”mechanism. Once an exception isthrown, we never go back to thepoint where the exception occurred.This is why Scheme’s call/ccmechanism is considered so specialand unique.

518CS 538 Spring 2003©

Example:class badValue extends Exception{ float value; badValue(float f) {value=f;} }

float sqrt(float val) throws badValue { if (val < 0.0) throw new badValue(val); else return (float) Math.sqrt(val); }

try { System.out.println( "Ans = " + sqrt(-123.0));} catch (badValue b) { System.out.println( "Can't take sqrt of "+b)}

519CS 538 Spring 2003©

Threads and Parallelism in JavaJava is one of the few “main stream”programming languages to explicitlyprovide for user-programmedparallelism in the form of threads.A Java programmer may organize aprogram as several threads that mayexecute concurrently.Even if the program is run on a uni-processor, use of threads may improveperformance. This is because thethreads can be multi-programmed,with threads switched automaticallyon I/O delays, page faults or evencache misses.A program that is designed to supportmultiple threads is also “prepared” forfuture upgrades to multiprocessors ormulti-threaded processors.

520CS 538 Spring 2003©

Java ThreadsIn Java any class that implements theRunnable interface can be started asa concurrent thread: interface Runnable {

public void run();

}

When the thread is started, themethod run begins to execute(perhaps concurrently with otherthreads of the main program).You create a thread using the Threadconstructor:

new Thread(RunnableObject)

Creating a thread does not start it;you must execute the start methodwithin the Thread object.

Page 131: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

521CS 538 Spring 2003©

When this is done, the run methodimmediately starts, and continuesuntil that method terminatesnormally, or it throws an uncaughtexception, or it is explicitly stopped,or the main program stops.On uniprocessors, thread execution isinterleaved; on multiprocessors ormultithreaded architectures executioncan be concurrent.

class DoSort implements Runnable { int [] data; DoSort(int[] in) {data=in;} public void run(){ // sort the data array; }}

522CS 538 Spring 2003©

class Test { public static void main(String args[]){ DoSort d = new DoSort(new int[1000]); Thread t1 = new Thread(d); t1.start();

// We can continue while t1 // does its sort }}

523CS 538 Spring 2003©

We can start multiple threads, andthe threads can use sleep to delay orsynchronize their execution:class PingPong implements Runnable { int delay; String word; PingPong(String s,int i){ delay=i;word=s;}; public void run(){ try { while(true){

System.out.print(word+" "); Thread.sleep(delay); }}

catch (InterruptedException e) {} }

524CS 538 Spring 2003©

public static void main(String args[]){ Thread t1 = new Thread( new PingPong("ping",33)); Thread t2 = new Thread( new PingPong("PONG",100)); t1.start(); t2.start(); }}

ping PONG ping ping PONG pingping ping PONG ping ping PONGping ...

Page 132: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

525CS 538 Spring 2003©

Synchronization in JavaWe often want threads to co-operate,typically in how they access shareddata structures.Since thread execution isasynchronous, the details of howthreads interact can be unpredictable.Consider a method update() {

n = n+1;

val = f(n);

}

that updates fields of an object.If two or more threads executeupdate concurrently, we might getunexpected or even illegal behavior.(Why?)

526CS 538 Spring 2003©

A Java method may be synchronized,which guarantees that at most onethread can execute the method at atime. Other threads wishing access,are forced to wait until the currentlyexecuting thread completes.Thusvoid synchronized update() { ... }

can safely be used to update anobject, even if multiple threads areactive.There is also a synchronizedstatement in Java that forces threadsto execute a block of codesequentially.synchronized(obj) {

obj.n = obj.n+1;

obj.val = f(obj.n);

}

527CS 538 Spring 2003©

Synchronization PrimitivesThe following operations are providedto allow threads to safely interact:wait() Sleep until awakenedwait(n) Sleep until awakened

or until n millisecondspass

notify() Wake up one sleepingthread

notifyAll() Wake up all sleepingthreads

Using these primitives, correctconcurrent access to a shared datastructure can be programed.

528CS 538 Spring 2003©

Consider a Buffer class in whichindependent threads may try to storeor fetch data objects:

class Buffer { private Queue q; Buffer() { q = new Queue(); } public synchronized void put(Object obj) { q.enqueue(obj); notify(); //Why is this needed? } public synchronized Object get() { while (q.isEmpty()) {

//Why a while loop? wait(); } return q.dequeue(); }}

Page 133: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

529CS 538 Spring 2003©

Locks, Semaphores andMonitors

Java’s synchronization mechanismsare based upon the notion of a lock. Alock is a special value that can beheld by at most one thread.If a thread holds a lock, it haspermission to do some “critical”operation like writing a sharedvariable or restructuring a shareddata object.If a thread wants to do an operationbut doesn’t hold the necessary lock, itmust wait until it gets the lock.In Java there is a lock associated witheach run-time object.

530CS 538 Spring 2003©

Lock Granularity and AccessThough each Java object has a lock,you often don’t want to lock andunlock each object you access.If you are manipulating a large datastructure (like a tree or hash table),acquiring the lock for each object inthe tree or table can be costly anderror-prone.Instead, it is common to create a lockcorresponding to a group of objects.Hence holding the lock to the root ofa tree may give you permission toaccess the whole tree.There is a danger though—if all ormost of a large structure is held byone thread, then other threads won’tbe able to access that structureconcurrently.

531CS 538 Spring 2003©

For example, a large shared data base(like one used to record currentbookings for an airline) shouldn’t beheld exclusively by one thread—hundreds of concurrent threads maywant to access it at any time. Anintermediate lock, like all reservationsfor a single fight, is more reasonable.There is also an issue of how long youhold a lock. The ideal is to haveexclusive access for as short a periodas is necessary. Work that is notsubject to interference by otherthreads (like computations using localvariables) should be done before alock is obtained. Hence Java’ssynchronized statement allows amethod to get exclusive access to anobject for a limited region, enhancingshared access.

532CS 538 Spring 2003©

Reading Assignment• C# Tutorial

(linked from class web page)

Page 134: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

533CS 538 Spring 2003©

DeadlockA variety of programming problemsappear in concurrent programs thatdon’t exist in ordinary sequentialprograms.The most serious of these is deadlock:Two or more threads hold locks thatother threads require. Each waits forthe other thread to release a neededlock, and no thread is able to execute.As an example of how deadlock mayoccur, consider two threads, t1 andt2 . Each requires two files, a masterfile and a log file. Since these files areshared, each has a lock.Assume t1 gets the lock for themaster file while t2 (at the sameinstant) gets the lock for the log file.

534CS 538 Spring 2003©

Now each is stuck. Each has one file,and will wait forever for the other fileto be released.In Java deadlock avoidance is whollyup to the programmer. There are nolanguage-level guarantees thatdeadlock can’t happen.Some languages have experimentedwith ways to help programmers avoiddeadlock:• If all locks must be claimed at once,

deadlock can be avoided. You eitherget all of them or none, but you can’tblock other threads while making noprogress yourself.

• Locks (and the resources theycontrol) can be ordered, with the rulethat you must acquire locks in the

535CS 538 Spring 2003©

proper order. Now two threads can’teach hold locks the other needs.

• The language can require that thelargest set of locks ever needed bedeclared in advance. When locks arerequested, the operating system cantrack what’s claimed and what maybe needed, and refuse to honorunsafe requests.

536CS 538 Spring 2003©

Fairness & StarvationWhen one thread has a lock, otherthreads who want the lock will besuspended until the lock is released.It can happen that a waiting threadmay be forced to wait indefinitely toacquire a lock, due to an unfairwaiting policy. A waiting thread thatnever gets a lock it needs due tounfair lock allocation faces starvation.As an example, if we place waitingthreads on a stack, newly arrivedthreads will get access to a lockbefore earlier arrivals. This can lead tostarvation. Most thread managers tryto be fair and guarantee that allwaiting threads have a fair chance toacquire a lock.

Page 135: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

537CS 538 Spring 2003©

How are Locks Implemented?Internally, Java needs operations toacquire a lock and release a lock.These operations can be implementedusing the notion of a semaphore.A semaphore is an integer value(often just a single bit) with twoatomic operations: up and down.up(s) increments s atomically.down(s) decrements s atomically.But if s is already zero, the processdoing the down operation is put in await state until s becomes positive(eventually some other process shoulddo an up operation).Now locks are easy to implement.You do a down(lock) to claim a lock.If someone else has it, you are forced

538CS 538 Spring 2003©

to wait until the lock is released. Ifthe lock value is > 0 you get it and allothers are “locked out.”When you want to release a lock, youdo up(lock) , which makes locknon-zero and eligible for anotherthread to claim.In fact, since only one thread will everhave a lock, the lock value needs tobe only one bit, with 1 meaningcurrently free and unlocked and 0meaning currently claimed andlocked.

539CS 538 Spring 2003©

MonitorsDirect manipulation of semaphores istedious and error-prone. If youacquire a lock but forget to release it,threads may be blocked forever.Depending on where down and upoperations are placed, it may bedifficult to understand howsynchronization is being performed.Few modern languages allow directuse of semaphores. Instead,semaphores are used in theimplementation of higher-levelconstructs like monitors.A monitor is a language constructthat guarantees that a block of codewill be executed synchronously (onethread at a time).

540CS 538 Spring 2003©

The Java synchronized statement isa form of monitor.Whensynchronized(obj) { ... }

is executed, “invisible” getLock andfreeLock operations are added:synchronized(obj) { getLock(obj)

...

freeLock(obj);

}

This allows the body of thesynchronized statement to executeonly when it has the lock for obj .Thus two different threads can neversimultaneously execute the body of asynchronized statement becausetwo threads can’t simultaneously holdobj ’s lock.

Page 136: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

541CS 538 Spring 2003©

In fact, synchronized methods arereally just methods whose bodies areenclosed in an invisiblesynchronized statement.If we execute obj.method()

where method is synchronized,method ’s body is executed as if itwere of the formsynchronized(obj) {

body of method

}

Operations like sleep , wait , notifyand notifyAll also implicitly causethreads to release locks, allowingother threads to proceed.

542CS 538 Spring 2003©

Reading Assignment• Pizza Tutorial

(linked from class web page)

543CS 538 Spring 2003©

C#C# is Microsoft’s answer to Java. Inmost ways it is very similar to Java,with some C++ concepts reintroducedand some useful new features.Similarities to Java include:• C# is object-based, with all objected

descended from class Object .

• Objects are created from classes usingnew. All objects are heap-allocatedand garbage collection is provided.

• All code is placed within methodswhich must be defined within classes.

• Almost all Java reserved words haveC# equivalents (many are identical).

• Classes have single inheritance.

544CS 538 Spring 2003©

• C# generates code for a virtualmachine to support cross-platformexecution.

• Interfaces are provided to capturefunctionality common to manyclasses.

• Exceptions are very similar in form toJava’s.

• Instance and static data within anobject must be initialized at point ofcreation.

Page 137: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

545CS 538 Spring 2003©

C# Improves Upon Some JavaFeatures

• Operators as well as methods can beoverloaded:

class Point { int x, y; static Point operator + ( Point p1, Point p2) { return new Point(p1.x+p2.x,

p1.y+p2.y); } }

• Switch statements may be indexed bystring literals.

• In a switch, fall throughs to the nextcase are disallowed (if non-empty).

• Goto’s are allowed.

• Virtual methods must be marked.

546CS 538 Spring 2003©

• Persistent objects (that may be storedacross executions) are available.

547CS 538 Spring 2003©

C# Adds Useful Features• Events and delegates are included to

handle asynchronous actions (likekeyboard or mouse actions).

• Properties allow user-defined readand write actions for fields. You canadd get and set methods to thedefinition of a field. For example,

class Customer {

private string name;

public string Name {

get { return name; }}

}

Customer c; ...

string s = c.Name;

548CS 538 Spring 2003©

• Indexers allow objects other thanarrays to be indexed. The [] operatoris overloadable. This allows you todefine the meaning ofobj[123] or obj["abc"]within any class definition.

• Collection classes may be directlyenumerated:foreach (int i in array) ...

• Fields, methods and constructors maybe defined within a struct as well as aclass. Structs are allocated within thestack instead of the heap, and arepassed by value. For example:

struct Point {

int x,y;

void reset () {

x=0; y=0; }

}

Page 138: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

549CS 538 Spring 2003©

• When an object is needed, a primitive(int , char , etc.) or a struct will beautomatically boxed or unboxedwithout explicit use of a wrapperclass (like Integer or Character ).Thus if method List.add expects anobject, you may write

List.add(123);and 123 will be boxed into anInteger object automatically.

• Enumerations are provided:enum Color {Red, Blue, Green};

• Rectangular arrays are provided:int [,] multi = new int[5,5];

• Reference, out and variable-lengthparameter lists are allowed.

• Pointers may be used in methodsmarked unsafe .

550CS 538 Spring 2003©

Reading Assignment• Python Tutorial

(linked from class web page)

551CS 538 Spring 2003©

PizzaPizza is an extension to Java developedin the late 90s by Odersky and Wadler.Pizza shows that many of the best ideasof functional languages can beincorporated into a “mainstream”language, giving it added power andexpressability.Pizza adds to Java:1. Parametric Polymorphism

Classes can be parameterized withtypes, allowing the creation of“custom” data types with fullcompile-time type checking.

2. First-class FunctionsFunctions can be passed, returned andstored just like other types.

552CS 538 Spring 2003©

3. Patterns and Value ConstructorsClasses can be subdivided into anumber of value constructors, andpatterns can be used to structure thedefinition of methods.

Page 139: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

553CS 538 Spring 2003©

Parametric PolymorphismJava allows a form of polymorphismby defining container classes (lists,stacks, queues, etc.) in terms of valuesof type Object .For example, to implement a linkedlist we might use:class LinkedList { Object value; LinkedList next; Object head() {return value;}

LinkedList tail(){return next;} LinkedList(Object O) { value = O; next = null;} LinkedList(Object O, LinkedList L){ value = O; next = L;}}

554CS 538 Spring 2003©

We use class Object because anyobject can be assigned to Object (allclasses must be a subclass ofObject ).Using this class, we can create alinked list of any subtype of Object .But,• We can’t guarantee that linked lists

are type homogeneous (contain only asingle type).

• We must unbox Object types backinto their “real” types when weextract list values.

• We must use wrapper classes likeInteger rather than int (becauseprimitive types like int aren’tobjects, and aren’t subclass ofObject ).

555CS 538 Spring 2003©

For example, to use LinkedList tobuild a linked list of int s we do thefollowing:

LinkedList L = new LinkedList(new Integer(123));

int i = ((Integer) L.head()).intValue();

This is pretty clumsy code. We’dprefer a mechanism that allows us tocreate a “custom version” ofLinkedList , based on the type wewant the list to contain.We can’t just call something like

LinkedList(int) orLinkedList(Integer) because

types can’t be passed as parameters.Parametric polymorphism is thesolution. Using this mechanism, wecan use type parameters to build a

556CS 538 Spring 2003©

“custom version” of a class from ageneral purpose class.C++ allows this using its templatemechanism. Pizza also allows typeparameters.In both languages, type parametersare enclosed in “angle brackets” (e.g.,LinkedList<T> passes T, a type, tothe LinkedList class).In Pizza we haveclass LinkedList<T> { T value; LinkedList<T> next; T head() {return value;} LinkedList<T> tail() { return next;} LinkedList(T O) { value = O; next = null;} LinkedList(T O,LinkedList<T> L) {value = O; next = L;}}

Page 140: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

557CS 538 Spring 2003©

When linked list objects are created(using new) no type qualifiers areneeded—the type of the constructor’sparameters are used. We can createLinkedList<int> L1 = new LinkedList(123);

int i = L1.head();

LinkedList<String> L2 = new LinkedList("abc");

String s = L2.head();

LinkedList<LinkedList<int> > L3 = new LinkedList(L1);

int j = L3.head().head();

558CS 538 Spring 2003©

Bounded PolymorphismIn Pizza we can use interfaces tobound the type parameters a classwill accept.Recall our Compare interface:interface Compare {

boolean lessThan(Object o1, Object o2);

}

We can specify that a parameterizedclass will only takes types thatimplement Compare:class LinkedList<T implements

Compare> { ... }

559CS 538 Spring 2003©

In fact, we can improve upon howinterfaces are defined and used.Recall that in method lessThan wehad to use parameters declared astype Object to be general enough tomatch (and accept) any object type.This leads to clumsy casting (withrun-time correctness checks) whenlessThan is implemented for aparticular type:class IntCompare implements Compare { public boolean lessThan(Object i1, Object i2){ return ( (Integer) i1).intValue() < ( (Integer )i2).intValue();}}

560CS 538 Spring 2003©

Pizza allows us to parameterize classdefinitions with type parameters, sowhy not do the same for interfaces?In fact, this is just what Pizza does.We can now define Compare asinterface Compare<T> { boolean lessThan(T o1, T o2);}

Now we define class LinkedList asclass LinkedList<T implements

Compare<T> > { ... }

Given this form of interfacedefinition, no casting (from typeObject ) is needed in classes thatimplement Compare:class IntCompare implements

Compare<Integer> { public boolean lessThan(Integer i1,

Integer i2){ return i1.intValue() < i2.intValue();}}

Page 141: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

561CS 538 Spring 2003©

First-class Functions in PizzaIn Java, functions are treated asconstants that may appear only inclasses.To pass a function as a parameter, youmust pass a class that contains thatfunction as a member. For example,class Fct { int f(int i) { return i+1; }}class Test {

static int call(Fct g, int arg) { return g.f(arg); }}

562CS 538 Spring 2003©

Changing the value of a function iseven nastier. Since you can’t assign toa member function, you have to usesubclassing to override an existingdefinition:class Fct2 extends Fct { int f(int i) { return i+111; }}

Computing new functions duringexecutions is nastier still, as Javadoesn’t have any notion of a lambda-term (that builds a new function).

563CS 538 Spring 2003©

Pizza makes functions first-class, asin ML. You can have functionparameters, variables and returnvalues. You can also define newfunctions within a method.The notation used to define the typeof a function value is(T 1,T 2, ...)->T 0

This says the function will take thelist (T 1,T 2, ...) as it argumentsand will return T0 as its result.Thus

(int)->int

represents the type of a method likeint plus1(int i) {return i+1;}

564CS 538 Spring 2003©

The notation used by Java for fixedfunctions still works. Thusstatic int f(int i){return 2*i;};

denotes a function constant, f .The definition static (int)->int g = f;

defines a field of type (int)->intnamed g that is initialized to thevalue of f .The definitionstatic int call((int)->int f, int i) {return f(i);};

defines a constant function that takesas parameters a function value oftype (int)->int and an int value.It calls the function parameter withthe int parameter and returns thevalue the function computes.

Page 142: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

565CS 538 Spring 2003©

Pizza also has a notation foranonymous functions (functionliterals), similar to fn in ML andlambda in Scheme. The notationfun (T 1 a 1, T 2 a 2, ...) -> T 0 {Body}

defines a nameless function witharguments declared as (T 1 a1, T 2 a2,

...) and a result type of T0. Thefunction’s body is computed byexecuting the block {Body} .For example,static (int)->int compose(

(int)->int f, (int)->int g){ return fun (int i) -> int {return f(g(i));};

}

defines a method named compose . Ittakes as parameters two functions, fand g, each of type (int)->int .

566CS 538 Spring 2003©

The function returns a function as itsresult. The type of the result is(int)->int and its value is thecomposition of functions f and g: return f(g(i));

Thus we can now have a call likecompose(f1,f2)(100)

which computes f1(f2(100)) .

567CS 538 Spring 2003©

With function parameters, somefamiliar functions can be readilyprogrammed:class Map { static int[] map((int)->int f, int[] a){ int [] ans = new int[a.length]; for (int i=0;i<a.length;i++) ans[i]=f(a[i]); return ans; };}

568CS 538 Spring 2003©

And we can make such operationspolymorphic by using parametricpolymorphism:class Map<T> { private static T dummy; Map(T val) {dummy=val;}; static T[] map((T)->T f,

T[] a){ T [] ans = (T[]) a.clone();

for (int i=0;i<a.length;i++) ans[i]=f(a[i]); return ans; };}

Page 143: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

569CS 538 Spring 2003©

Algebraic Data TypesPizza also provides “algebraic datatypes” which allow a type to bedefined as a number of cases. This isessentially the pattern-orientedapproach we saw in ML.A list is a good example of the utilityof algebraic data types. Lists come intwo forms, null and non-null, and wemust constantly ask which form oflist we currently have. With patterns,the need to consider both forms isenforced, leading to a more reliableprogramming style.In Pizza, patterns are modeled as“cases” and grafted onto the existingswitch statement (this formulation isa bit clumsy):

570CS 538 Spring 2003©

class List { case Nil; case Cons(char head, List tail); int length(){ switch(this){ case Nil: return 0; case Cons(char x, List t): return 1 + t.length(); } }}

571CS 538 Spring 2003©

And guess what! We can useparametric polymorphism along withalgebraic data types:class List<T> { case Nil; case Cons(T head, List<T> tail); int length(){ switch(this){ case Nil: return 0; case Cons(T x, List<T> t): return 1 + t.length(); } }}

572CS 538 Spring 2003©

Enumerations as AlgebraicData Types

We can use algebraic data types toobtain a construct missing from Javaand Pizza—enumerations.We simply define an algebraic datatype whose constructors are notparameterized:class Color { case Red; case Blue; case Green; String toString() { switch(this) { case Red: return "red"; case Blue: return "blue"; case Green: return "green"; } }}

Page 144: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

573CS 538 Spring 2003©

This approach is better than simplydefining enumeration values asconstant (final) integers:

final int Red = 1;

final int Blue = 2;

final int Green = 3;

With the algebraic data typeapproach, Red, Blue and Green , arenot integers. They are constructorsfor the type Color . This leads to morethorough type checking.

574CS 538 Spring 2003©

PythonOne of the newest and mostinnovative scripting languages isPython, developed by Guido vanRossum in the mid-90s. Python isnamed after the BBC “Monty Python”television series.Python blends the expressive powerand flexibility of earlier scriptinglanguages with the power of object-oriented programming languages.It offers a lot to programmers:• An interactive development mode as

well as an executable “batch” modefor completed programs.

• Very reasonable execution speed. LikeJava, Python programs are compiled.Also like Java, the compiled code is in

575CS 538 Spring 2003©

an intermediate language for whichan interpreter is written. Like Javathis insulates Python from many ofthe vagaries of the actual machineson which it runs, giving it portabilityof an equivalent level to that of Java.Unlike Java, Python retains theinteractivity for which interpretersare highly prized.

• Python programs require nocompilation or linking. Nevertheless,the semi-compiled Python programstill runs much faster than itstraditionally interpreted rivals such asthe shells, awk and perl.

• Python is freely available on almostall platforms and operating systems(Unix, Linux, Windows, MacOs, etc.)

576CS 538 Spring 2003©

• Python is completely object oriented.It comes with a full set of objectedoriented features.

• Python presents a first class objectmodel with first class functions andmultiple inheritance. Also includedare classes, modules, exceptions andlate (run-time) binding.

• Python allows a clean and openprogram layout. Python code is lesscluttered with the syntactic “noise”of declarations and scope definitions.Scope in a Python program is definedby the indentation of the code inquestion. Python thus breaks withcurrent language designs in thatwhite space has now once againacquired significance.

Page 145: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

577CS 538 Spring 2003©

• Like Java, Python offers automatedmemory management through run-time reference counting and garbagecollection of unreferenced objects.

• Python can be embedded in otherproducts and programs as a controllanguage.

• Python’s interface is well exposed andis reasonably small and simple.

• Python’s license is truly public.Python programs can be used or soldwithout copyright restrictions.

• Python is extendable. You candynamically load compiled Python,Python source, or even dynamicallyload new machine (object) code toprovide new features and newfacilities.

578CS 538 Spring 2003©

• Python allows low-level access to itsinterpreter. It exposes its internalplumbing to a significant degree toallow programs to make use of theway the plumbing works.

• Python has a rich set of externallibrary services available. Thisincludes, network services, a GUI API(based on tcl/Tk), Web support forthe generation of HTML and the CGIinterfaces, direct access to databases,etc.

579CS 538 Spring 2003©

Using PythonPython may be used in eitherinteractive or batch mode.In interactive mode you start up thePython interpreter and enterexecutable statements. Just naming avariable (a trivial expression)evaluates it and echoes its value.For example (>>> is the Pythoninteractive prompt):>>> 11

>>> a=1

>>> a1

>>> b=2.5

>>> b2.5

580CS 538 Spring 2003©

>>> a+b3.5

>>> print a+b3.5

You can also incorporate Pythonstatements into a file and executethem in batch mode. One way to dothis is to enter the commandpython file.py

where file.py contains the Pythoncode you want executed. Be carefulthough; in batch mode you must usea print (or some other outputstatement) to force output to beprinted. Thus1

a=1

a

Page 146: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

581CS 538 Spring 2003©

b=2.5

b

a+b

print a+b

when run in batch mode prints only3.5 (the output of the printstatement).You can also run Python programs asUnix shell scripts by adding the line#! /usr/bin/env pythonto the head of your Python file.(Since # begins Python comments,you can also feed the sameaugmented file directly to the Pythoninterpreter)

582CS 538 Spring 2003©

Python Command FormatIn Python, individual primitivecommands and expressions mustappear on a single line.This means that a = 1

+b

does not assign 1+b to a! Rather, itassigns 1 to a, then evaluates +b.If you wish to span more than oneline, you must use \ to escape theline:a = 1 \

+b

is equivalent toa = 1 +b

583CS 538 Spring 2003©

Compound statements, like ifstatements and while loops, can spanmultiple lines, but individualstatements within an if or while (ifthey are primitive) must appear one asingle line.

Why this restriction?With it, ; ’s are mostly unnecessary!A ; at the end of a statement is legalbut usually unnecessary, as the end-of-line forces the statement to end.You can use a ; to squeeze more thanone statement onto a line, if youwish:a=1; b=2 ; c=3

584CS 538 Spring 2003©

Identifiers and Reserved WordsIdentifiers look much the same as inmost programming languages. Theyare composed of letters, digits andunderscores. Identifiers must beginwith a letter or underscore. Case issignificant. As in C and C++,identifiers that begin with anunderscore often have specialmeaning.

Python contains a fairly typical set ofreserved words:and del for is raiseassert elif from lambda returnbreak else global not tryclass except if or whilecontinue exec import passdef finally in print

Page 147: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

585CS 538 Spring 2003©

Numeric TypesThere are four numeric types:1. Integers, represented as a 32 bit (or

longer) quantity. Digits sequences(possibly) signed are integer literals:1 -123 +456

2. Long integers, of unlimited precision.An integer literal followed by an l orL is a long integer literal:12345678900000000000000L

3. Floating point values, represented as a64 bit floating point number. Literalsare of fixed decimal or exponentialform:123.456 1e10 6.0231023

4. Complex numbers, represented as apair of floating point numbers. Incomplex literals j or J is used to

586CS 538 Spring 2003©

denote the imaginary part of thecomplex value:

1.0+2.0j -22.1j 10e10J+20.0

There is no character type. A literallike 'a' or "c" denotes a string oflength one.

There is no boolean type. A zeronumeric value (any form), or None(the equivalent of void) or an emptystring, list, tuple or dictionary istreated as false; other values aretreated as true.Hence "abc" and "def"

is treated as true in an if , since bothstrings are non-empty.

587CS 538 Spring 2003©

Arithmetic OperatorsOp Description** Exponentiation- Unary plus+ Unary minus~ Bit-wise complement

(int or long only)* Multiplication/ Division% Remainder- Binary plus+ Binary minus<< Bit-wise left shift (int or long only)>> Bit-wise right shift (int or long only)& Bit-wise and (int or long only)| Bit-wise or (int or long only)^ Bit-wise Xor (int or long only)< Less than> Greater than

588CS 538 Spring 2003©

>= Greater than or equal<= Less than or equal== Equal!= Not equaland Boolean andor Boolean ornot Boolean not

Page 148: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

589CS 538 Spring 2003©

Operator Precedence LevelsListed from lowest to highest:or Boolean ORand Boolean ANDnot Boolean NOT<, <=, >, >=, <>, !=, == Comparisons| Bitwise OR^ Bitwise XOR& Bitwise AND<<, >> Shifts+, - Addition and subtraction*, /, % Multiplication, division,

remainder** Exponentiation+, - Positive, negative (unary)~ Bitwise not

590CS 538 Spring 2003©

Arithmetic Operator UseArithmetic operators may be usedwith any arithmetic type, withconversions automatically applied.Bit-wise operations are restricted tointegers and long integers. The resulttype is determined by the “generality”of the operands. (Long is moregeneral than int, float is more generalthan both int and long, complex isthe most general numeric type). Thus>>> 1+23

>>> 1+111L112L

>>> 1+1.12.1

>>> 1+2.0j(1+2j)

591CS 538 Spring 2003©

Unlike almost all other programminglanguages, relational operators maybe “chained” (as in standardmathematics).Therefore a > b > c

means (a > b) and (b > c)

592CS 538 Spring 2003©

Assignment StatementsIn Python assignment is a statementnot an expression.Thus a+(b=2)

is illegal.Chained assignments are allowed:a = b = 3

Since Python is dynamically typed,the type (and value) associated withan identifier can change because ofan assignment:>>> a = 0

>>> print a0

>>> a = a + 0L

>>> print a

Page 149: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

593CS 538 Spring 2003©

0L

>>> a = a + 0.0

>>> print a0.0

>>> a = a + 0.0J

>>> print a0j

594CS 538 Spring 2003©

If and While StatementsPython contains if and whilestatements that are fairly similar tothose found in C and Java.There are some significant differencesthough.A line that contains an if , else orwhile ends in a “: ”. Thus we mightwrite: if a > 0:

b = 1

Moreover the indentation of the thenpart is significant! You don’t need {and } in Python because allstatements indented at the same levelare assumed to be part of the sameblock.

595CS 538 Spring 2003©

In the following Python statementsif a>0:

b=1

c=2

d=3

the assignments to b and c constitutethen part; the assignment to dfollows the if statement, and isindependent of it. In interactive modea blank line is needed to allow theinterpreter to determine where the ifstatement ends; this blank line is notneeded in batch mode.

596CS 538 Spring 2003©

The if StatementThe full form of the if statement isif expression:

statement(s)

elif expression:

statement(s)

...

else:

statement(s)

Note those pesky : ’s at the end of theif , elif and else lines. Theexpressions following the if andoptional elif lines are evaluateduntil one evaluates to true. Then thefollowing statement(s), delimited byindentation, are executed. If noexpression evaluates to true, thestatements following the else areexecuted.

Page 150: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

597CS 538 Spring 2003©

Use of else and elif are optional; a“bare” if may be used.If any of the lists of statements is tobe null, use pass to indicate thatnothing is to be done.For exampleif a>0:

b=1

elif a < 0:

pass

else

b=0

This if sets b to 1 if a is > 0; it sets bto 0 if a == 0 , and does nothing if a <0.

598CS 538 Spring 2003©

While LoopsPython contains a fairly conventionalwhile loop:

while expression:

body

Note the “: ” that ends the headerline. Also, indentation delimits thebody of the loop; no braces areneeded. For example,>>> a=0; b=0

>>> while a < 5:

... b = b+a**2

... a= a+1

...

>>> print a,b5 30

599CS 538 Spring 2003©

Break, Continue and Else inLoops

Like C, C++ and Java, Python allowsuse of break within a loop to forceloop termination. For example,>>> a=1

>>> while a < 10:

... if a+a == a**2:

... break

... else:

... a=a+1

...

>>> print a2

600CS 538 Spring 2003©

A continue may be used to force thenext loop iteration:>>> a=1

>>> while a < 100:

... a=a+1

... if a%2==0:

... continue

... a=3*a

...

>>> print a105

Page 151: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

601CS 538 Spring 2003©

Python also allows you to add anelse clause to a while (or for ) loop.The syntax iswhile expression:

body

else:

statement(s)

The else statements are executedwhen the termination conditionbecomes false, but not when the loopis terminated with a break . As aresult, you can readily program“search loops” that need to handlethe special case of search failure:

602CS 538 Spring 2003©

>>> a=1

>>> while a < 1000:

... if a**2 == 3*a-1:

... print "winner: ",a

... break

... a=a+1

... else:

... print "No match"

...

No match

603CS 538 Spring 2003©

Sequence TypesPython includes three sequence types:strings, tuples and lists. All sequencetypes may be indexed, using a verygeneral indexing system.Strings are sequences of characters;tuples and lists may contain any typeor combination of types (like Schemelists).Strings and tuples are immutable(their components may not bechanged). Lists are mutable, and beupdated, much like arrays.Strings may be delimited by either asingle quote (' ) or a double quote (" )or even a triple quote (''' or """ ). Agiven string must start and stop withthe same delimiter. Triply quotedstrings may span multiple lines. There

604CS 538 Spring 2003©

is no character type or value;characters are simply strings oflength 1. Legal strings include'abc' "xyz" '''It's OK!'''

Lists are delimited by “[ “ and “] ”.Empty (or null lists) are allowed. Validlist literals include [1,2,3] ["one",1] [['a'],['b'],['c']] []

Tuples are a sequence of valuesseparated by commas. A tuple may beenclosed within parentheses, but thisisn’t required. A empty tuple is () . Asingleton tuple ends with a comma(to distinguish it from a simple scalarvalue).Thus (1,) or just 1, is a valid tupleof length one.

Page 152: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

605CS 538 Spring 2003©

Indexing Sequence TypesPython provides a very general andpowerful indexing mechanism. Anindex is enclosed in brackets, just likea subscript in C or Java. Indexingstarts at 0.Thus we may have>>> 'abcde'[2]'c'

>>> [1,2,3,4,5][1]2

>>> (1.1,2.2,3.3)[0]1.1

Using an index that’s too big raises anIndexError exception:>>> 'abc'[3]IndexError: string index out ofrange

606CS 538 Spring 2003©

Unlike most languages, you can usenegative index values; these simplyindex from the right:>>> 'abc'[-1]'c'

>>> [5,4,3,2,1][-2]2

>>> (1,2,3,4)[-4]1

You may also access a slice of asequence value by supplying a rangeof index values. The notation is

data[i:j]

which selects the values in data thatare >=i and < j . Thus>>> 'abcde'[1:2]'b'

>>> 'abcde'[0:3]'abc'

607CS 538 Spring 2003©

>>> 'abcde'[2:2]''

You may omit a lower or upper boundon a range. A missing lower bounddefaults to 0 and a missing upperbound defaults to the maximum legalindex. For example,>>> [1,2,3,4,5][2:][3, 4, 5]

>>> [1,2,3,4,5][:3][1, 2, 3]

An upper bound that’s too large in arange is interpreted as the maximumlegal index:>>> 'abcdef'[3:100]'def'

You may use negative values inranges too—they’re interpreted asbeing relative to the right end of thesequence:

608CS 538 Spring 2003©

>>> 'abcde'[0:-2]'abc'

>>> 'abcdefg'[-5:-2]'cde'

>>> 'abcde'[-3:]'cde'

>>> 'abcde'[:-1]'abcd'

Since arrays may be assigned to, youmay assign a slice to change severalvalues at once:>>> a=[1,2,3,4]

>>> a[0:2]=[-1,-2]

>>> a[-1, -2, 3, 4]

>>> a[2:]=[33,44]

>>> a[-1, -2, 33, 44]

Page 153: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

609CS 538 Spring 2003©

The length of the value assigned to aslice need not be the same size as theslice itself, so you can shrink orexpand a list by assigning slices:>>> a=[1,2,3,4,5]

>>> a[2:3]=[3.1,3.2]

>>> a[1, 2, 3.1, 3.2, 4, 5]

>>> a[4:]=[]

>>> a[1, 2, 3.1, 3.2]

>>> a[:0]=[-3,-2,-1]

>>> a[-3, -2, -1, 1, 2, 3.1, 3.2]

610CS 538 Spring 2003©

Other Operations onSequences

Besides indexing and slicing, anumber of other useful operations areprovided for sequence types (strings,lists and tuples).These include:

+ (catenation):>>> [1,2,3]+[4,5,6][1, 2, 3, 4, 5, 6]

>>> (1,2,3)+(4,5)(1, 2, 3, 4, 5)

>>> (1,2,3)+[4,5]TypeError: illegal argumenttype for built-in operation

>>> "abc"+"def"'abcdef'

611CS 538 Spring 2003©

• * (Repetition):>>> 'abc'*2'abcabc'

>>> [3,4,5]*3[3, 4, 5, 3, 4, 5, 3, 4, 5]

• Membership (in , not in )>>> 3 in [1,2,3,4]1

>>> 'c' in 'abcde'1

• max and min :>>> max([3,8,-9,22,4])22

>>> min('aa','bb','abc')'aa'

612CS 538 Spring 2003©

Operations on ListsAs well as the operations available forall sequence types (including lists),there are many other usefuloperations available for lists. Theseinclude:• count (Count occurrences of an item

in a list):>>> [1,2,3,3,21].count(3)2

• index (Find first occurrence of anitem in a list):

>>> [1,2,3,3,21].index(3)2

>>> [1,2,3,3,21].index(17)ValueError: list.index(x): xnot in list

Page 154: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

613CS 538 Spring 2003©

• remove (Find and remove an itemfrom a list):

>>> a=[1,2,3,4,5]>>> a.remove(4)>>> a[1, 2, 3, 5]

>>> a.remove(17)ValueError: list.remove(x): xnot in list

• pop (Fetch and remove i-th elementof a list):

>>> a=[1,2,3,4,5]>>> a.pop(3)4

>>> a[1, 2, 3, 5]

>>> a.pop()5

>>> a[1, 2, 3]

614CS 538 Spring 2003©

• reverse a list:>>> a=[1,2,3,4,5]>>> a.reverse()>>> a[5, 4, 3, 2, 1]

• sort a list:>>> a=[5,1,4,2,3]>>> a.sort()>>> a[1, 2, 3, 4, 5]

• Create a range of values:>>> range(1,5)[1, 2, 3, 4]

>>> range(1,10,2)[1, 3, 5, 7, 9]

615CS 538 Spring 2003©

DictionariesPython also provides a dictionary type(sometimes called an associativearray). In a dictionary you can use anumber (including a float orcomplex), string or tuple as an index.In fact any immutable type can be anindex (this excludes lists anddictionaries).An empty dictionary is denoted { } .A non-empty dictionary may bewritten as{ key 1:value 1, key 2:value 2, ... }

For example,c={ 'bmw':540, 'lexus':'sc 430',

'porsche':'boxster'}

616CS 538 Spring 2003©

You can use a dictionary much like anarray, indexing it using keys, andupdating it by assigning a new valueto a key:>>> c['bmw']540

>>> c['bmw']='m5'

>>> c['honda']='accord'

You can delete a value using del :>>> del c['honda']>>> c['honda']

KeyError: honda

Page 155: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

617CS 538 Spring 2003©

You can also check to see if a givenkey is valid, and also list all keys,values, or key-value pairs in use:>>> c.has_key('edsel')0

>>> c.keys()['bmw', 'porsche', 'lexus']

>>> c.values()['m5', 'boxster', 'sc 430']

>>> c.items()[('bmw', 'm5'), ('porsche','boxster'), ('lexus', 'sc 430')]

618CS 538 Spring 2003©

For LoopsIn Python’s for loops, you don’texplicitly control the steps of aniteration. Instead, you provide asequence type (a string, list orsequence), and Python automaticallysteps through the values.Like a while loop, you must end thefor loop header with a “: ” and thebody is delimited using indentation.For example,>>> for c in 'abc':

... print c

...

a

b

c

619CS 538 Spring 2003©

The range function, which creates alist of values in a fixed range is usefulin for loops:>>> a=[5,2,1,4]

>>> for i in range(0,len(a)):

... a[i]=2*a[i]

...

>>> print a[10, 4, 2, 8]

620CS 538 Spring 2003©

You can use an else with for loopstoo. Once the values in the specifiedsequence are exhausted, the else isexecuted unless the for is exitedusing a break . For example, for i in a:

if i < 0:

print 'Neg val:',i

break

else:

print 'No neg vals'

Page 156: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

621CS 538 Spring 2003©

Function DefinitionsFunction definitions are of the formdef name(args): body

The symbol def tells Python that afunction is to be defined. Thefunction is called name and args is atuple defining the names of thefunction’s arguments. The body ofthe function is delimited usingindentation. For example,def fact(n):

if n<=1:

return 1

else:

return n*fact(n-1)

>>> fact(5)120

>>> fact(20L)

622CS 538 Spring 2003©

2432902008176640000L

>>> fact(2.5)3.75

>>> fact(2+1J)(1+3j)

Scalar parameters are passed byvalue; mutable objects are allocatedin the heap and hence are passed (ineffect) by reference:>>> def asg(ar):

... a[1]=0

... print ar

...

>>> a=[1,2,3,4.5]

>>> asg(a)[1, 0, 3, 4.5]

623CS 538 Spring 2003©

Arguments may be given a defaultvalue, making them optional in a call.Optional parameters must followrequired parameters in definitions.For example, >>> def expo(val,exp=2):

... return val**exp

...

>>> expo(3,3)27

>>> expo(3)9

>>> expo()TypeError: not enough arguments;expected 1, got 0

624CS 538 Spring 2003©

A variable number of arguments isallowed; you prefix the last formalparameter with a * ; this parameter isbound to a tuple containing all theactual parameters provided by thecaller:>>> def sum(*args):... sum=0... for i in args:... sum=sum+i... return sum...

>>> sum(1,2,3)6

>>> sum(2)2

>>> sum()0

Page 157: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

625CS 538 Spring 2003©

You may also use the name of formalparameters in a call, making the orderof parameters less important:>>> def cat(left="[",body="",

right="]"):

... return left+body+right

...

>>> cat(body='xyz');'[xyz]'

>>> cat(body='hi there!' ,left='--[')'--[hi there!]'

626CS 538 Spring 2003©

Scoping Rules in FunctionsEach function body has its own localnamespace during execution. Anidentifier is resolved (if possible) inthe local namespace, then (ifnecessary) in the global namespace.Thus>>> def f():

... a=11

... return a+b

...

>>> b=2;f()13

>>> a=22;f()13

>>> b=33;f()44

627CS 538 Spring 2003©

Assignments are to local variables,even if a global exists. To force anassignment to refer to a globalidentifier, you use the declaration

global id

which tells Python that in thisfunction id should be consideredglobal rather than local. For example,>>> a=1;b=2

>>> def f():

... global a

... a=111;b=222

...

>>> f();print a,b111 2

628CS 538 Spring 2003©

Other Operations on FunctionsSince Python is interpreted, you candynamically create and executePython code.The function eval(string)interprets string as a Pythonexpression (in the current executionenvironment) and returns what iscomputed. For example,>>> a=1;b=2

>>> eval('a+b')3

Page 158: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

629CS 538 Spring 2003©

exec(string) executes string asarbitrary Python code (in the currentenvironment):>>> a=1;b=2

>>> exec('for op in "+-*/":print(eval("a"+op+"b"))')3

-1

2

0

execfile(string) executes thecontents of the file whose pathnameis specified by string . This can beuseful in loading an existing set ofPython definitions.

630CS 538 Spring 2003©

The expressionlambda args: expression

creates an anonymous function withargs as its argument list andexpression as it body. For example,>>> (lambda a:a+1)(2)3

And there are definitions of map,reduce and filter to map afunction to a list of values, to reducea list (using a binary function) and toselect values from a list (using apredicate):>>> def double(a):

... return 2*a;

...

>>> map(double,[1,2,3,4])[2, 4, 6, 8]

631CS 538 Spring 2003©

>>> def sum(a,b):

... return a+b

...

>>> reduce(sum,[1,2,3,4,5])15

>>> def even(a):

... return not(a%2)

...

>>> filter(even,[1,2,3,4,5])[2, 4]

632CS 538 Spring 2003©

I/O in PythonThe easiest way to print informationin Python is the print statement.You supply a list of values separatedby commas. Values are converted tostrings (using the str() function)and printed to standard out, with aterminating new line automaticallyincluded. For example,>>> print "1+1=",1+11+1= 2

If you don’t want the automatic endof line, add a comma to the end ofthe print list:>>> for i in range(1,11):

... print i,

...

1 2 3 4 5 6 7 8 9 10

Page 159: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

633CS 538 Spring 2003©

For those who love C’s printf ,Python provides a nice formattingcapability using a printf-likenotation. The expression

format % tuple

formats a tuple of values using aformat string. The detailed formattingrules are those of C’s printf . Thus>>> print "%d+%d=%d" % (10,20,10+20)10+20=30

634CS 538 Spring 2003©

File-oriented I/OYou open a file usingopen(name,mode)

which returns a “file object.”name is a string representing the file’spath name; mode is a stringrepresenting the desired accessmode('r' for read, 'w' for write,etc.).Thus>>> f=open("/tmp/f1","w");>>> f<open file '/tmp/f1', mode 'w' atdecd8>

opens a temp file for writing.The command f.read(n)

reads n bytes (as a string).

635CS 538 Spring 2003©

f.read() reads the whole file into astring. At end-of-file, f.read returnsthe null string:>>> f = open("/tmp/ttt","r")

>>> f.read(3)'aaa'

>>> f.read(5)' bbb '

>>> f.read()'ccc\012ddd eee fff\012g h i\012'

>>> f.read()''

f.readline() reads a whole line ofinput, and f.readlines() reads thewhole input file into a list of strings:>>> f = open("/tmp/ttt","r")

>>> f.readline()'aaa bbb ccc\012'

>>> f.readline()

636CS 538 Spring 2003©

'ddd eee fff\012'

>>> f.readline()'g h i\012'

>>> f.readline()''

>>> f = open("/tmp/ttt","r")

>>> f.readlines()['aaa bbb ccc\012', 'ddd eeefff\012', 'g h i\012']

f.write(string) writes a stringto file object f ; f.close() closes afile object:>>> f = open("/tmp/ttt","w")

>>> f.write("abcd")

>>> f.write("%d %d"%(1,-1))

>>> f.close()

>>> f = open("/tmp/ttt","r")

>>> f.readlines()['abcd1 -1']

Page 160: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

637CS 538 Spring 2003©

Classes in PythonPython contains a class creationmechanism that’s fairly similar towhat’s found in C++ or Java.There are significant differencesthough:• All class members are public.

• Instance fields aren’t declared. Rather,you just create fields as needed byassignment (often in constructors).

• There are class fields (shared by allclass instances), but there are noclass methods. That is, all methodsare instance methods.

638CS 538 Spring 2003©

• All instance methods (includingconstructors) must explicitly providean initial parameter that representsthe object instance. This parameter istypically called self . It’s roughly theequivalent of this in C++ or Java.

639CS 538 Spring 2003©

Defining ClassesYou define a class by executing a classdefinition of the formclass name:

statement(s)

A class definition creates a classobject from which class instances maybe created (just like in Java). Thestatements within a class definitionmay be data members (to be sharedamong all class instances) as well asfunction definitions (prefixed by adef command). Each function musttake (at least) an initial parameterthat represents the class instancewithin which the function (instancemethod) will operate. For example,

640CS 538 Spring 2003©

class Example: cnt=1 def msg(self): print "Bo"+"o"*Example.cnt+

"!"*self.n

>>> Example.cnt1

>>> Example.msg<unbound method Example.msg>

Example.msg is unbound because wehaven’t created any instances of theExample class yet.We create class instances by using theclass name as a function:>>> e=Example()

>>> e.msg()AttributeError: n

We get the AttributeErrormessage regarding n because wehaven’t defined n yet! One way to do

Page 161: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

641CS 538 Spring 2003©

this is to just assign to it, using theusual field notation:>>> e.n=1

>>> e.msg()Boo!

>>> e.n=2;Example.cnt=2

>>> e.msg()Booo!!

We can also call an instance methodby making the class object an explicitparameter:>>> Example.msg(e)Booo!!

It’s nice to have data membersinitialized when an object is created.This is usually done with aconstructor, and Python allows thistoo.

642CS 538 Spring 2003©

A special method named __init__ iscalled whenever an object is created.This method takes self as its firstparameter; other parameters (possiblymade optional) are allowed.We can therefore extend ourExample class with a constructor:class Example: cnt=1 def __init__(self,nval=1): self.n=nval def msg(self): print "Bo"+"o"*Example.cnt+ "!"*self.n

>>> e=Example()

>>> e.n1

>>> f=Example(2)

>>> f.n2

643CS 538 Spring 2003©

You can also define the equivalent ofJava’s toString method by defininga member function named__str__(self) .For example, if we add

def __str__(self):

return "<%d>"%self.n

to Example ,then we can include Example objectsin print statements:>>> e=Example(2)

>>> print e<2>

644CS 538 Spring 2003©

InheritanceLike any language that supportsclasses, Python allows inheritancefrom a parent (or base) class. In fact,Python allows multiple inheritance inwhich a class inherits definitions frommore than one parent.When defining a class you specifyparents classes as follows:class name(parent classes):

statement(s)

The subclass has access to its owndefinitions as well as those availableto its parents. All methods are virtual,so the most recent definition of amethod is always used.

Page 162: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

645CS 538 Spring 2003©

class C:

def DoIt(self): self.PrintIt() def PrintIt(self): print "C rules!"

class D(C): def PrintIt(self): print "D rules!" def TestIt(self): self.DoIt()

dvar = D() dvar.TestIt()

D rules!

646CS 538 Spring 2003©

If you specify more than one parentfor a class, lookup is depth-first, leftto right, in the list of parentsprovided. For example, givenclass A(B,C): ...

we first look for a non-localdefinition in B (and its parents), thenin C (and its parents).

647CS 538 Spring 2003©

Operator OverloadingYou can overload definitions of all ofPython’s operators to apply to newlydefined classes. Each operator has acorresponding method name assignedto it. For example, + uses __add__ , -uses __sub__ , etc.

648CS 538 Spring 2003©

Givenclass Triple: def __init__(self,A=0,B=0,C=0): self.a=A self.b=B self.c=C def __str__(self): return "(%d,%d,%d)"% (self.a,self.b,self.c) def __add__(self,other):

return Triple(self.a+other.a,self.b+other.b,

self.c+other.c)

the following codet1=Triple(1,2,3)

t2=Triple(4,5,6)

print t1+t2

produces(5,7,9)

Page 163: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

649CS 538 Spring 2003©

ExceptionsPython provides an exceptionmechanism that’s quite similar to theone used by Java.You “throw” an exception by using araise statement:

raise exceptionValue

There are numerous predefinedexceptions, includingOverflowError (arithmeticoverflow), EOFError (when end-of-file is hit), NameError (when anundeclared identifier is referenced),etc.

650CS 538 Spring 2003©

You may define your own exceptionsas subclasses of the predefined classException :class badValue(Exception):

def __init__(self,val):

self.value=val

You catch exceptions in Python’sversion of a try statement:try:

statement(s)

except exceptionName 1, id 1:

statement(s)

...

except exceptionName n, id n:

statement(s)

As was the case in Java, an exceptionraised within the try body is handledby an except clause if the raisedexception matches the class named in

651CS 538 Spring 2003©

the except clause. If the raisedexception is not matched by anyexcept clause, the next enclosingtry is considered, or the exception isreraised at the point of call.For example, using our badValueexception class, def sqrt(val): if val < 0.0: raise badValue(val) else: return cmath.sqrt(val)

try: print "Ans =",sqrt(-123.0)except badValue,b: print "Can’t take sqrt of",

b.value

When executed, we getAns = Can’t take sqrt of -123.0

652CS 538 Spring 2003©

ModulesPython contains a module featurethat allows you to access Python codestored in files or libraries. If you havea source file mydefs.py thecommand import mydefs

will read in all the definitions storedin the file. What’s read in can be seenby executingdir(mydefs)

To access an imported definition, youqualify it with the name of themodule. For example,mydefs.fct

accesses fct which is defined inmodule mydefs .

Page 164: pages.cs.wisc.edupages.cs.wisc.edu/~fischer/cs538.s08/LectureAll.s03.4up.pdf · CS 538 Spring 2003 1 © CS 538 Introduction to the Theory and Design of Programming Languages Charles

653CS 538 Spring 2003©

To avoid explicit qualification you canuse the commandfrom modulename import id 1, id 2,...

This makes id 1, id 2, ... availablewithout qualification. For example,>>> from test import sqrt

>>> sqrt(123)(11.0905365064+0j)

You can use the commandfrom modulename import *

to import (without qualification) allthe definitions in modulename.

654CS 538 Spring 2003©

The Python LibraryOne of the great strengths of Pythonis that it contains a vast number ofmodules (at least several hundred)known collectively as the PythonLibrary. What makes Python reallyuseful is the range of prewrittenmodules you can access. Included arenetwork access modules, multimediautilities, data base access, and muchmore.Seewww.python.org/doc/lib

for an up-to-date listing of what’savailable.