The Promises of Functional Programming

Total Page:16

File Type:pdf, Size:1020Kb

The Promises of Functional Programming S cieNTIFic P ROGRAMMING Editors: Konstantin Läufer, [email protected] Konrad Hinsen, [email protected] THE PROMISES OF FUNC T IONAL PROGRAMMING By Konrad Hinsen Adopting a functional programming style could make your programs more robust, more compact, and more easily parallelizable. However, mastering it requires some effort. ince the early days of com- (Alonzo Church’s λ-calculus) and as a probably Mathematica, although most puting, software development programming technique in the 1950s Mathematica users don’t write com- S techniques have changed (John McCarthy’s Lisp language)— plex functional programs. Another almost as much as computer tech- functional programming. Although example of symbolic processing is the nology itself. Ever more powerful functional programming has been widely used fast Fourier transform li- hardware made it possible to write very popular in computer science brar y, FF TW,1 which uses a function- ever more complex software, which research for several decades, its use al code optimizer written in OCaml both required ever better develop- for writing real-life programs is rela- to produce optimized C code for a ment tools and techniques and made tively recent. Of the many reasons Fourier transform of a given length. their implementation possible. Pro- for this, the two most important are In numerical applications, functional grammers thus moved from machine that functional programming is very programming doesn’t yet play an im- code to assembly languages and then different from traditional program- portant role. Perhaps the most ambi- problem-oriented programming lan- ming (also referred to as imperative tious project to introduce it into the guages, which have evolved to inte- programming) and thus requires a lot number-crunching world was Law- grate techniques such as structural of learning and unlearning, and that rence Livermore National Laborato- and object-oriented programming. computer hardware implements the ry’s Streams and Iteration in a Single Another evolution went from mono- imperative programming model, so Assignment Language (SISAL) proj- lithic programs via separately compil- imperative programs are easier to ect, which started in 1983. SISAL is a able modules and libraries to software compile into efficient machine code functional language with paralleliza- component technologies. However, in than functional programs. However, tion support, designed specifically for one respect, today’s popular program- several clear signs indicate a growing the needs of scientific applications. ming techniques are still the same as interest in functional programming Unfortunately, it didn’t attract the those the pioneers used: our programs techniques—recent programming attention it deserved, and funding consist of statements that modify data languages (such as Sun’s Fortress or stopped in 1996. Today, SISAL lives stored in the computer’s memory until Microsoft’s F#) have the explicit goal on as an open source project (http:// that memory contains the desired re- of supporting it. The reason is that sorceforge.net/projects/sisal). sult. This approach closely resembles functional programming has several This article’s purpose is to explain how a computer works at the hardware advantages for concurrent and par- what functional programming is and level: the processor fetches data from allel programming. Experience also how it differs from traditional impera- memory, performs elementary opera- suggests that functional programs are tive programming. I also explain how tions on it, and writes the result back more robust and easier to test than functional programming helps with to a memory cell. imperative ones. concurrent and parallel program- In fact, this approach is so com- In scientific computing, research- ming. The language I use in the ex- mon that most of you have probably ers have mainly used functional pro- amples is Clojure, a modern dialect never questioned it. And yet, an al- gramming for symbolic processing. In of Lisp (see the sidebar “Clojure and ternative approach was developed fact, the most widely used functional the Lisp Family”), but everything said as mathematical theory in the 1930s programming language in science is here applies equally to other function- 86 Copublished by the IEEE CS and the AIP 1521-9615/09/$25.00 © 2009 IEEE COMPUTING IN SC IEN C E & ENGINEERING CLOJURE AND THE LISP FAMILY he language used in the main text’s examples is Clojure, a modern dialect Tof the Lisp language family. Lisp stands for “list processing,” which hints at the motivations of John McCarthy, who developed the first Lisp language in the late 1950s for use in artificial intelligence research. Today, the most widely al languages, only the syntax will be used Lisp dialects are Scheme and Common Lisp. different. If you’re interested in func- The Lisp language family’s distinctive feature is the principle that “code is tional programming, you should also data.” Lisp provides a syntax for a simple yet flexible data structure—nested lists. read (or reread) Jerzy Karczmarczuk’s It then defines how to interpret nested lists that follow specific conventions as 1999 article in this magazine,2 which executable code. The advantage of expressing code in a data structure is that illustrates how functional program- Lisp code can easily generate (and then execute) other Lisp code, a fact that pro- ming can yield elegant solutions to grammers have exploited from the beginning through Lisp macros, the world’s problems in mathematical modeling. first meta-programming system and probably still its most powerful one. Lisp has the reputation of being slow, but that isn’t true anymore. Many The Basics modern compilers can produce code that can compete with C in performance The fundamental principle of func- when given appropriate optimization hints. However, it remains very difficult tional programming is that you re- to produce programs that are both efficient and portable between compilers alize a computation by composing and platforms. functions. The word “function” is Clojure is a recent Lisp dialect that sets itself apart by three features: it has used here in the mathematical sense— four highly optimized data structures (lists, vectors, maps, and sets) designed a mapping from input values to output for pure functional programming, it offers extensive support for concurrency, values—whereas what most program- and it was designed for the Java Virtual Machine with the goal of easy inter- ming languages call “functions” are operability with other JVM languages, including Java itself. For more informa- subroutines that return a value. One tion about Clojure, see its Web site at http://clojure.org. important difference is that a func- tion in the mathematical sense always produces the same output when given the same input. An operation such as write a useful program in a functional guage like Python and JavaScript). If n “get the next line from a file” isn’t a style, but keep reading. is zero, the return value of countdown function because each time you call, What replaces loops in functional is (list 0), a list containing the sin- it produces a different return value. programs is recursion. A function gle element 0. Otherwise (we’re look- Another important difference is that is called recursive if it calls itself— ing at lines four to six now), the return a mathematical function doesn’t “do” directly or indirectly. Of course, value is a list constructed by prepend- anything other than return a value. It calling itself makes sense only if the ing n to the return value of count- isn’t supposed to have side effects—for arguments change between calls. down for (- n 1), which is Clojure’s example, it shouldn’t write anything to Moreover, if you ever want to get out way of writing n-1. The function call a file or change a variable in memory. of the call-yourself chain, a recursive (countdown 1) thus returns (cons If a program is composed of func- function must return without calling 1 (countdown 0)), which, after ex- tions, and functions aren’t supposed itself for some arguments. Let’s look ecuting the recursive function call, to change any variables, then what are at a simple example of recursion: becomes (cons 1 (list 0)). Look- variables good for? Nothing, and that’s ing up the definitions of the functions why functional programming doesn’t (defn countdown [n] cons and list will tell you that the have variables. This is probably the (if (zero? n) final result is the two-element list (1 biggest surprise to those who discover (list 0) 0). This simple example illustrates functional programming because vari- (cons n how to use recursion for looping: with ables are so very fundamental to our (countdown each recursive call, the argument be- traditional ways of writing programs. (- n 1))))) comes smaller, up to the point where The other missing fundamental con- it’s handled directly without any fur- cept is loops. After all, what’s the point These six lines define a function ther recursion. of a loop if nothing can change be- countdown of a single argument n, A closer look at the chain of recur- tween iterations because there are no which should be an integer (although sive calls to countdown also reveals variables? By now, you might be con- this is neither said nor enforced, Clo- why functional programming can live vinced that it’s absolutely impossible to jure being a dynamicallly typed lan- without variables. At each recursive JULY/AUGU S T 2009 87 S cieNTIFic P ROGRAMMING call, n decreases by one, which looks a to the programmer. As is so often the are called higher-order functions, as op- bit as if n were a variable decremented case, both approaches have their good posed to first-order functions whose from its initial value to zero; indeed, and bad sides.
Recommended publications
  • Programming Paradigms & Object-Oriented
    4.3 (Programming Paradigms & Object-Oriented- Computer Science 9608 Programming) with Majid Tahir Syllabus Content: 4.3.1 Programming paradigms Show understanding of what is meant by a programming paradigm Show understanding of the characteristics of a number of programming paradigms (low- level, imperative (procedural), object-oriented, declarative) – low-level programming Demonstrate an ability to write low-level code that uses various address modes: o immediate, direct, indirect, indexed and relative (see Section 1.4.3 and Section 3.6.2) o imperative programming- see details in Section 2.3 (procedural programming) Object-oriented programming (OOP) o demonstrate an ability to solve a problem by designing appropriate classes o demonstrate an ability to write code that demonstrates the use of classes, inheritance, polymorphism and containment (aggregation) declarative programming o demonstrate an ability to solve a problem by writing appropriate facts and rules based on supplied information o demonstrate an ability to write code that can satisfy a goal using facts and rules Programming paradigms 1 4.3 (Programming Paradigms & Object-Oriented- Computer Science 9608 Programming) with Majid Tahir Programming paradigm: A programming paradigm is a set of programming concepts and is a fundamental style of programming. Each paradigm will support a different way of thinking and problem solving. Paradigms are supported by programming language features. Some programming languages support more than one paradigm. There are many different paradigms, not all mutually exclusive. Here are just a few different paradigms. Low-level programming paradigm The features of Low-level programming languages give us the ability to manipulate the contents of memory addresses and registers directly and exploit the architecture of a given processor.
    [Show full text]
  • Functional Languages
    Functional Programming Languages (FPL) 1. Definitions................................................................... 2 2. Applications ................................................................ 2 3. Examples..................................................................... 3 4. FPL Characteristics:.................................................... 3 5. Lambda calculus (LC)................................................. 4 6. Functions in FPLs ....................................................... 7 7. Modern functional languages...................................... 9 8. Scheme overview...................................................... 11 8.1. Get your own Scheme from MIT...................... 11 8.2. General overview.............................................. 11 8.3. Data Typing ...................................................... 12 8.4. Comments ......................................................... 12 8.5. Recursion Instead of Iteration........................... 13 8.6. Evaluation ......................................................... 14 8.7. Storing and using Scheme code ........................ 14 8.8. Variables ........................................................... 15 8.9. Data types.......................................................... 16 8.10. Arithmetic functions ......................................... 17 8.11. Selection functions............................................ 18 8.12. Iteration............................................................. 23 8.13. Defining functions ...........................................
    [Show full text]
  • The Machine That Builds Itself: How the Strengths of Lisp Family
    Khomtchouk et al. OPINION NOTE The Machine that Builds Itself: How the Strengths of Lisp Family Languages Facilitate Building Complex and Flexible Bioinformatic Models Bohdan B. Khomtchouk1*, Edmund Weitz2 and Claes Wahlestedt1 *Correspondence: [email protected] Abstract 1Center for Therapeutic Innovation and Department of We address the need for expanding the presence of the Lisp family of Psychiatry and Behavioral programming languages in bioinformatics and computational biology research. Sciences, University of Miami Languages of this family, like Common Lisp, Scheme, or Clojure, facilitate the Miller School of Medicine, 1120 NW 14th ST, Miami, FL, USA creation of powerful and flexible software models that are required for complex 33136 and rapidly evolving domains like biology. We will point out several important key Full list of author information is features that distinguish languages of the Lisp family from other programming available at the end of the article languages and we will explain how these features can aid researchers in becoming more productive and creating better code. We will also show how these features make these languages ideal tools for artificial intelligence and machine learning applications. We will specifically stress the advantages of domain-specific languages (DSL): languages which are specialized to a particular area and thus not only facilitate easier research problem formulation, but also aid in the establishment of standards and best programming practices as applied to the specific research field at hand. DSLs are particularly easy to build in Common Lisp, the most comprehensive Lisp dialect, which is commonly referred to as the “programmable programming language.” We are convinced that Lisp grants programmers unprecedented power to build increasingly sophisticated artificial intelligence systems that may ultimately transform machine learning and AI research in bioinformatics and computational biology.
    [Show full text]
  • IJIRT | Volume 2 Issue 6 | ISSN: 2349-6002
    © November 2015 | IJIRT | Volume 2 Issue 6 | ISSN: 2349-6002 .Net Surbhi Bhardwaj Dronacharya College of Engineering Khentawas, Haryana INTRODUCTION as smartphones. Additionally, .NET Micro .NET Framework (pronounced dot net) is Framework is targeted at severely resource- a software framework developed by Microsoft that constrained devices. runs primarily on Microsoft Windows. It includes a large class library known as Framework Class Library (FCL) and provides language WHAT IS THE .NET FRAMEWORK? interoperability(each language can use code written The .NET Framework is a new and revolutionary in other languages) across several programming platform created by Microsoft for languages. Programs written for .NET Framework developingapplications. execute in a software environment (as contrasted to hardware environment), known as Common It is a platform for application developers. Language Runtime (CLR), an application virtual It is a Framework that supports Multiple machine that provides services such as Language and Cross language integration. security, memory management, and exception handling. FCL and CLR together constitute .NET IT has IDE (Integrated Development Framework. Environment). FCL provides user interface, data access, database Framework is a set of utilities or can say connectivity, cryptography, web building blocks of your application system. application development, numeric algorithms, .NET Framework provides GUI in a GUI and network communications. Programmers manner. produce software by combining their own source code with .NET Framework and other libraries. .NET is a platform independent but with .NET Framework is intended to be used by most new help of Mono Compilation System (MCS). applications created for the Windows platform. MCS is a middle level interface. Microsoft also produces an integrated development .NET Framework provides interoperability environment largely for .NET software called Visual between languages i.e.
    [Show full text]
  • 15-150 Lectures 27 and 28: Imperative Programming
    15-150 Lectures 27 and 28: Imperative Programming Lectures by Dan Licata April 24 and 26, 2012 In these lectures, we will show that imperative programming is a special case of functional programming. We will also investigate the relationship between imperative programming and par- allelism, and think about what happens when the two are combined. 1 Mutable Cells Functional programming is all about transforming data into new data. Imperative programming is all about updating and changing data. To get started with imperative programming, ML provides a type 'a ref representing mutable memory cells. This type is equipped with: • A constructor ref : 'a -> 'a ref. Evaluating ref v creates and returns a new memory cell containing the value v. Pattern-matching a cell with the pattern ref p gets the contents. • An operation := : 'a ref * 'a -> unit that updates the contents of a cell. For example: val account = ref 100 val (ref cur) = account val () = account := 400 val (ref cur) = account 1. In the first line, evaluating ref 100 creates a new memory cell containing the value 100, which we will write as a box: 100 and binds the variable account to this cell. 2. The next line pattern-matches account as ref cur, which binds cur to the value currently in the box, in this case 100. 3. The next line updates the box to contain the value 400. 4. The final line reads the current value in the box, in this case 400. 1 It's important to note that, with mutation, the same program can have different results if it is evaluated multiple times.
    [Show full text]
  • Functional Programming Laboratory 1 Programming Paradigms
    Intro 1 Functional Programming Laboratory C. Beeri 1 Programming Paradigms A programming paradigm is an approach to programming: what is a program, how are programs designed and written, and how are the goals of programs achieved by their execution. A paradigm is an idea in pure form; it is realized in a language by a set of constructs and by methodologies for using them. Languages sometimes combine several paradigms. The notion of paradigm provides a useful guide to understanding programming languages. The imperative paradigm underlies languages such as Pascal and C. The object-oriented paradigm is embodied in Smalltalk, C++ and Java. These are probably the paradigms known to the students taking this lab. We introduce functional programming by comparing it to them. 1.1 Imperative and object-oriented programming Imperative programming is based on a simple construct: A cell is a container of data, whose contents can be changed. A cell is an abstraction of a memory location. It can store data, such as integers or real numbers, or addresses of other cells. The abstraction hides the size bounds that apply to real memory, as well as the physical address space details. The variables of Pascal and C denote cells. The programming construct that allows to change the contents of a cell is assignment. In the imperative paradigm a program has, at each point of its execution, a state represented by a collection of cells and their contents. This state changes as the program executes; assignment statements change the contents of cells, other statements create and destroy cells. Yet others, such as conditional and loop statements allow the programmer to direct the control flow of the program.
    [Show full text]
  • Functional and Imperative Object-Oriented Programming in Theory and Practice
    Uppsala universitet Inst. för informatik och media Functional and Imperative Object-Oriented Programming in Theory and Practice A Study of Online Discussions in the Programming Community Per Jernlund & Martin Stenberg Kurs: Examensarbete Nivå: C Termin: VT-19 Datum: 14-06-2019 Abstract Functional programming (FP) has progressively become more prevalent and techniques from the FP paradigm has been implemented in many different Imperative object-oriented programming (OOP) languages. However, there is no indication that OOP is going out of style. Nevertheless the increased popularity in FP has sparked new discussions across the Internet between the FP and OOP communities regarding a multitude of related aspects. These discussions could provide insights into the questions and challenges faced by programmers today. This thesis investigates these online discussions in a small and contemporary scale in order to identify the most discussed aspect of FP and OOP. Once identified the statements and claims made by various discussion participants were selected and compared to literature relating to the aspects and the theory behind the paradigms in order to determine whether there was any discrepancies between practitioners and theory. It was done in order to investigate whether the practitioners had different ideas in the form of best practices that could influence theories. The most discussed aspect within FP and OOP was immutability and state relating primarily to the aspects of concurrency and performance. ​ ​ ​ ​ ​ ​ This thesis presents a selection of representative quotes that illustrate the different points of view held by groups in the community and then addresses those claims by investigating what is said in literature.
    [Show full text]
  • Functional Javascript
    www.it-ebooks.info www.it-ebooks.info Functional JavaScript Michael Fogus www.it-ebooks.info Functional JavaScript by Michael Fogus Copyright © 2013 Michael Fogus. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/ institutional sales department: 800-998-9938 or [email protected]. Editor: Mary Treseler Indexer: Judith McConville Production Editor: Melanie Yarbrough Cover Designer: Karen Montgomery Copyeditor: Jasmine Kwityn Interior Designer: David Futato Proofreader: Jilly Gagnon Illustrator: Robert Romano May 2013: First Edition Revision History for the First Edition: 2013-05-24: First release See http://oreilly.com/catalog/errata.csp?isbn=9781449360726 for release details. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. Functional JavaScript, the image of an eider duck, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trade‐ mark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
    [Show full text]
  • Unit 2 — Imperative and Object-Oriented Paradigm
    Programming Paradigms Unit 2 — Imperative and Object-oriented Paradigm J. Gamper Free University of Bozen-Bolzano Faculty of Computer Science IDSE PP 2018/19 Unit 2 – Imperative and Object-oriented Paradigm 1/38 Outline 1 Imperative Programming Paradigm 2 Abstract Data Types 3 Object-oriented Approach PP 2018/19 Unit 2 – Imperative and Object-oriented Paradigm 2/38 Imperative Programming Paradigm Outline 1 Imperative Programming Paradigm 2 Abstract Data Types 3 Object-oriented Approach PP 2018/19 Unit 2 – Imperative and Object-oriented Paradigm 3/38 Imperative Programming Paradigm Imperative Paradigm/1 The imperative paradigm is the oldest and most popular paradigm Based on the von Neumann architecture of computers Imperative programs define sequences of commands/statements for the computer that change a program state (i.e., set of variables) Commands are stored in memory and executed in the order found Commands retrieve data, perform a computation, and assign the result to a memory location Data ←→ Memory CPU (Data and Address Program) ←→ The hardware implementation of almost all Machine code computers is imperative 8B542408 83FA0077 06B80000 Machine code, which is native to the C9010000 008D0419 83FA0376 computer, and written in the imperative style B84AEBF1 5BC3 PP 2018/19 Unit 2 – Imperative and Object-oriented Paradigm 4/38 Imperative Programming Paradigm Imperative Paradigm/2 Central elements of imperative paradigm: Assigment statement: assigns values to memory locations and changes the current state of a program Variables refer
    [Show full text]
  • Comparative Studies of Programming Languages; Course Lecture Notes
    Comparative Studies of Programming Languages, COMP6411 Lecture Notes, Revision 1.9 Joey Paquet Serguei A. Mokhov (Eds.) August 5, 2010 arXiv:1007.2123v6 [cs.PL] 4 Aug 2010 2 Preface Lecture notes for the Comparative Studies of Programming Languages course, COMP6411, taught at the Department of Computer Science and Software Engineering, Faculty of Engineering and Computer Science, Concordia University, Montreal, QC, Canada. These notes include a compiled book of primarily related articles from the Wikipedia, the Free Encyclopedia [24], as well as Comparative Programming Languages book [7] and other resources, including our own. The original notes were compiled by Dr. Paquet [14] 3 4 Contents 1 Brief History and Genealogy of Programming Languages 7 1.1 Introduction . 7 1.1.1 Subreferences . 7 1.2 History . 7 1.2.1 Pre-computer era . 7 1.2.2 Subreferences . 8 1.2.3 Early computer era . 8 1.2.4 Subreferences . 8 1.2.5 Modern/Structured programming languages . 9 1.3 References . 19 2 Programming Paradigms 21 2.1 Introduction . 21 2.2 History . 21 2.2.1 Low-level: binary, assembly . 21 2.2.2 Procedural programming . 22 2.2.3 Object-oriented programming . 23 2.2.4 Declarative programming . 27 3 Program Evaluation 33 3.1 Program analysis and translation phases . 33 3.1.1 Front end . 33 3.1.2 Back end . 34 3.2 Compilation vs. interpretation . 34 3.2.1 Compilation . 34 3.2.2 Interpretation . 36 3.2.3 Subreferences . 37 3.3 Type System . 38 3.3.1 Type checking . 38 3.4 Memory management .
    [Show full text]
  • Functional Programming Lecture 1: Introduction
    Functional Programming Lecture 13: FP in the Real World Viliam Lisý Artificial Intelligence Center Department of Computer Science FEE, Czech Technical University in Prague [email protected] 1 Mixed paradigm languages Functional programming is great easy parallelism and concurrency referential transparency, encapsulation compact declarative code Imperative programming is great more convenient I/O better performance in certain tasks There is no reason not to combine paradigms 2 3 Source: Wikipedia 4 Scala Quite popular with industry Multi-paradigm language • simple parallelism/concurrency • able to build enterprise solutions Runs on JVM 5 Scala vs. Haskell • Adam Szlachta's slides 6 Is Java 8 a Functional Language? Based on: https://jlordiales.me/2014/11/01/overview-java-8/ Functional language first class functions higher order functions pure functions (referential transparency) recursion closures currying and partial application 7 First class functions Previously, you could pass only classes in Java File[] directories = new File(".").listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isDirectory(); } }); Java 8 has the concept of method reference File[] directories = new File(".").listFiles(File::isDirectory); 8 Lambdas Sometimes we want a single-purpose function File[] csvFiles = new File(".").listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getAbsolutePath().endsWith("csv"); } }); Java 8 has lambda functions for that File[] csvFiles = new File(".")
    [Show full text]
  • Notes on Functional Programming with Haskell
    Notes on Functional Programming with Haskell H. Conrad Cunningham [email protected] Multiparadigm Software Architecture Group Department of Computer and Information Science University of Mississippi 201 Weir Hall University, Mississippi 38677 USA Fall Semester 2014 Copyright c 1994, 1995, 1997, 2003, 2007, 2010, 2014 by H. Conrad Cunningham Permission to copy and use this document for educational or research purposes of a non-commercial nature is hereby granted provided that this copyright notice is retained on all copies. All other rights are reserved by the author. H. Conrad Cunningham, D.Sc. Professor and Chair Department of Computer and Information Science University of Mississippi 201 Weir Hall University, Mississippi 38677 USA [email protected] PREFACE TO 1995 EDITION I wrote this set of lecture notes for use in the course Functional Programming (CSCI 555) that I teach in the Department of Computer and Information Science at the Uni- versity of Mississippi. The course is open to advanced undergraduates and beginning graduate students. The first version of these notes were written as a part of my preparation for the fall semester 1993 offering of the course. This version reflects some restructuring and revision done for the fall 1994 offering of the course|or after completion of the class. For these classes, I used the following resources: Textbook { Richard Bird and Philip Wadler. Introduction to Functional Program- ming, Prentice Hall International, 1988 [2]. These notes more or less cover the material from chapters 1 through 6 plus selected material from chapters 7 through 9. Software { Gofer interpreter version 2.30 (2.28 in 1993) written by Mark P.
    [Show full text]