Paradigms and Programming


Touretzky Reading: Chapter 1

Touretzky Exercises: 1.5,1.11, 1.12,1.13,1.19,1.20,1.22, 1.24, 1.25, 1.26


Paradigms are a way of thinking about the world, a way of organizing "objective facts" that is consistant with some or all of our world-view.

Example: Invasion of S. Vietnam by the North is an "objective fact." Two different paradigms interpreted these facts differently. One paradigm said the soviets are trying to take over the world and the U.S. should stop them, the other said the U.S. had no business being there- it was a local problem. From the same facts, two different interpretations were drawn.

Paradigms can create very strange iterpretations of facts, but this does not make them "wrong." Think about the "facts" that were available in the 16th century regarding the Earth and the Sun:

The Sun-centered and Earth-centered theories were instances where these facts were interpreted differently by two different paradigms.

Consider the "celestial spheres" interpretation of the Copernican model of the universe. The backers of celestial spheres proposal considered the Copernican approach a mathematical "hack" to make the calculations easier.

Copernicus also had trouble explaining why we did not observe the violent rotation of the earth; his paradigm chose to ignore this issue. Paradigms in the sciences can dictate what a scientist (you!) think is important, unimportant, interesting, boring, and (more generally) how you interpret "facts" you are given. The danger here is not understand that what appear to be "facts" are generally filtered through some paradigm; sometimes old paradigms have to be exchanged for new ones.

Programming Paradigms

Currently, there are three major programming paradigms: Procedural (sometimes called "declarative" or "block-structured"), Object-Oriented, and Functional. Here are some examples from each of the paradigms:

Procedural		Object-Oriented			Functional
FORTRAN (V, 90)		Simula (68)			Lisp
Cobol			Smalltalk			ML
Algol (Algol-68)	C++				FP
Pascal			Self				Scheme
Modula (2, 2+, 3)	Modula 3			Prolog
Ada (9X)		Emerald	(Dylan?)
Basic (Visual)		
C (C++)		
It should be noted that it is not the case that one can't program procedurally in Lisp, or O-O in C, it is just that a language which is designed for a particular programming paradigm makes (at least in theory) doing that type of programming easier.

We aren't going to dwell here on the relative strengths and weaknesses of the paradigms- that's the subject of 3410. We are going to focus on functional programming throughout this course.

Functional Programming

Functional programming (similar to both of the other paradigms) attempts to decompose the process of constructing programs into smaller and smaller sub- pieces with the hope that these smaller pieces are more managable (understandable?) . At the point we reach a small, managable problem in the functional programming world we (naturally) write a function . Let us do without a strict definition here and simply say that a function computes its value from its arguments (parameters) only , no global variables allowed! Further, functions in general don't modify their arguments. If you think about this for a second, an interesting property of functions can be observed: Given the same parameters, a function always returns the same result. (How could it do otherwise, it doesn't use global variables?) These functions have many of the same properties that mathematical "functions" do... this is not a coincidence! (What would happen if the sin function on your calculator used global variables?!?) These small function are combined- synthesized - into larger (of course) functions to compute some larger ( and presumably more complex) result.

Why would we want to program this way? Here are some reasons:

  1. With a little practice, they are pretty easy to construct.
  2. They are very easy to read.
  3. They are very easy to debug.
  4. If you are really energetic, you can prove some "mathematical" properties about them (such as correctness).
The list about sounds a lot like marketing hype, what's the story here? As for property 1, this is somewhat subjective so it is left to the reader to judge this (after taking this course!). Properties 2 and 3 are related to the fact that functions don't use global state in computing their results and therefore it is easier to understand what their behavior is. If you know the behavior of a function over its inputs, you completely understand it. Also, when you are debugging a program written functionally, all you need to consider is how to compute the correct results from the parameters given... this is a roundabout way of saying that functions are stateless. Property number 4 is left to some other courses, but consider an example: You (the computer) know some formal properties of the function PLUS and the MINUS. If you are given an expression (in Pascal-like notatation): MINUS(PLUS(X,1),1) what can you say about its result? What if MINUS or PLUS weren't functions but were computations that depended on global variables? How about: MINUS(PLUS,(X,Y),Y)

So, What's the matter here?

If everythings so wonderful in the land of functional programming, why doesn't everybody like it? What's the catch?

The catch is that functional programming can be difficult (especially at first) for people who were originally trained in one (or two) of the other paradigms. Functional programming (in a strict sense) doesn't permit global variables, local variables, assignment, and iteration. It is true that not all problems can be simply and/or easily expressed without constructs of this sort, so towards the end of the quarter we'll be talking about ways that functional programming can be used without the strict requirements of no globals, no locals, no assignment, no iteration, etc. However, towards the beginning of the course those that stray from the path of functional programming and try to use these constructs will be punished....

Principles Of Software Design

The principles of good software design are orthogonal to the issues surrounding programming paradigms, that is to say that you can pursue good software design in any programming and in all (well, maybe most) programming languages. However, the design of software (or at least the good design of software) is a series of trade-offs. A crucial trade off that has to be considered is the one between program effeciency and programmer effeciency. In earlier years this trade-off was a no-brainer: people time was cheap and computer time was expensive, so you didn't care how much time the people spent getting the program to work, only that when it worked it worked fast. Today, this situation is considerably more complicated. There are still situations where the computing resources are being stretched to the limit and we must concentrate on making our programs run faster or occupy less space (thus chosing program efficiency) but this is certainly not every case. Perhaps, it is not even the common case. Consider the phenomenal success of the PC software called PowerBuilder (or Visual Basic). These have traded program efficiency for programmer efficiency.

The granddaddy of all programmer efficiency trade-offs is Lisp. Programmer efficiency is the effective use of programmer time. This "time" should be taken as whole though, not simply just the time to write the code. Don't forget to the time to debug the code, understand and (re)use other people's code, and maintain/update old code that has to be changed to reflect new circumstances/applications. Having said all of this about programmer time, probably the single most important factor in the time it takes to code, debug, and maintain software is the complexity of the system being worked on. One can apply both the general features of good software design as well as some of the particular properties of functional programming towards reducing software complexity.

For the purposes of this course, you can be sure that we will not encourage to think about thinks like, "How do I make my programmer smaller?" "How do I make my program run faster?" or "How does the system really implement this function?" We are expecting to you maximize the programmer efficiency in your programs and in their associated designs. Abelson and Sussman say it pretty well when they say, "... programs must be written for people to read, and only incidentally for machines to execute." But the number one line on this subject comes from probably the most important computer scientist of all time, Donald Knuth, who said: "Premature optimization is the root of all evil."

Where does the Lisp come in?

You are going to learn a great many things about Lisp this
quarter. I'm going to shamelessly steal some text from Kurt Eiselt's
notes about lisp. Here it goes:

[...In this course you'll be learing about] the Common LISP programming language. Well, everything was going along just fine until we mentioned LISP, eh? You may have heard ugly things about LISP: there are too many parentheses, it's only for artificial intelligence, it's hard to learn, and so on. If you heard these myths at Tech, you probably heard them from people who had the language jammed down their throats in one or two weeks after having studied Pascal for two years. But these are in fact just myths, as we hope you'll see by the end of the quarter. LISP will be the language used in this course, and there are lots of good reasons for doing so:

1. LISP started out as a purely functional programming language, and still retains much of that flavor. At the very least, it still encourages a functional programming style, and that's going to help us in this course.

2. LISP is especially good for processing complex hierarchical data structures using recursion. In fact, it is so surprisingly good that those of you who have learned something about processing these sorts of data structures using pointers will find it hard to believe that it could be so easy (LISP does all the pointer management for you).

3. LISP is the second oldest general purpose programming language in use today (FORTRAN is the oldest). As such, LISP has the benefit of lots of people who have devoted lots of years to making it better. This shows up in the form of some of the most sophisticated programming tools (editors, debuggers, etc.) in existence.

4. Most programming languages are designed so that compilation is efficient, often at the expense of things like consistency and usability. LISP on the other hand was designed (and continues to evolve) to maintain mathematical consistency and usability, sometimes at the expense of making the computer work a little harder.

5. Because of its age, LISP is incredibly well documented.

6. LISP has a uniform simple syntax, and there is no distinction between program and data.

7. In its "normal" state, LISP is an interpreted language. That is, code is executed immediately, and no separate compile stage is necessary (although compiling LISP code is both possible and desirable). Interpreted languages are highly interactive and give immediate feedback, making LISP an increasingly popular tool for the rapid prototyping of complex software systems such as new language compilers, graphics systems, and user interfaces.

8. LISP is highly extensible. In other words, it's very easy to build new languages on top of LISP by adding functions. This feature is in large part responsible for LISP's longevity. As new programming paradigms emerged over time, many programming languages fell by the wayside, while LISP was extended to accommodate the new paradigms.

9. The Common LISP standard makes LISP programs very portable. Portability lets you migrate an application from one platform to another without having to rewrite bunches of code. This is an important thing for you budding software entrepreneurs to remember.

10. LISP has automatic storage management. Memory is allocated as it's needed on the fly, and memory that is no longer needed is "garbage collected" dynamically as well. There's seldom a need to "declare" data structures in advance.

11. LISP also has dynamic typing, which means you no longer have to make data type declarations. LISP does type-checking and necessary conversions at run-time.

12. Finally, LISP is the favored language for artificial intelligence work, at least in the United States, so if you're interested in AI, this is the language to know. And even if you're not interested, AI is a required course for CS majors at Tech, and it's taught using LISP, so LISP is still the language to know.


Back To The CS2360 Home Page
Ian Smith (iansmith@cc.gatech.edu)

Last Modified 5 Jan 95 by Ian Smith (iansmith@cc.gatech.edu)