Input, output, and sequence

Similar documents
Animations involving numbers

Functions that return lists

Animations that make decisions

For this chapter, switch languages in DrRacket to Advanced Student Language.

Shorthand for values: variables

Intro. Scheme Basics. scm> 5 5. scm>

Conditionals. Chapter Making decisions

the NXT-G programming environment

Racket Style Guide Fall 2017

The name of our class will be Yo. Type that in where it says Class Name. Don t hit the OK button yet.

Have the students look at the editor on their computers. Refer to overhead projector as necessary.

Lab 7: OCaml 12:00 PM, Oct 22, 2017

CSCI 1100L: Topics in Computing Lab Lab 11: Programming with Scratch

Hello World! Computer Programming for Kids and Other Beginners. Chapter 1. by Warren Sande and Carter Sande. Copyright 2009 Manning Publications

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

Lecture Transcript While and Do While Statements in C++

The design recipe. Readings: HtDP, sections 1-5. (ordering of topics is different in lectures, different examples will be used)

6.001 Notes: Section 8.1

If Statements, For Loops, Functions

Functional abstraction. What is abstraction? Eating apples. Readings: HtDP, sections Language level: Intermediate Student With Lambda

Functional abstraction

(Refer Slide Time 6:48)

CS450 - Structure of Higher Level Languages

OrbBasic Lesson 1 Goto and Variables: Student Guide

6.001 Notes: Section 6.1

Divisibility Rules and Their Explanations

Text Input and Conditionals

OrbBasic 1: Student Guide

[ the academy_of_code] Senior Beginners

SCHEME AND CALCULATOR 5b

Lecture 4: examples of topological spaces, coarser and finer topologies, bases and closed sets

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Repetition Through Recursion

Part II Composition of Functions

Lab 7c: Rainfall patterns and drainage density

Getting Started. Excerpted from Hello World! Computer Programming for Kids and Other Beginners

Excel Basics Fall 2016

6.001 Notes: Section 15.1

First Java Program - Output to the Screen

[Video] and so on... Problems that require a function definition can be phrased as a word problem such as the following:

XP: Backup Your Important Files for Safety

HOUR 4 Understanding Events

Access Intermediate

printf( Please enter another number: ); scanf( %d, &num2);

CS Introduction to Data Structures How to Parse Arithmetic Expressions

Programming Languages. Thunks, Laziness, Streams, Memoization. Adapted from Dan Grossman s PL class, U. of Washington

Case Study: Undefined Variables

Excel Basics Rice Digital Media Commons Guide Written for Microsoft Excel 2010 Windows Edition by Eric Miller

Problem Solving through Programming In C Prof. Anupam Basu Department of Computer Science & Engineering Indian Institute of Technology, Kharagpur

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Using the Zoo Workstations

1.2 Adding Integers. Contents: Numbers on the Number Lines Adding Signed Numbers on the Number Line

Access Intermediate

Preprocessor Directives

Yup, left blank on purpose. You can use it to draw whatever you want :-)

Do a domain analysis by hand-drawing three or more pictures of what the world program will look like at different stages when it is running.

The compiler is spewing error messages.

COPYRIGHTED MATERIAL. Dipping Your Toe into Python. Part I. Chapter 1: Programming Basics and Strings. Chapter 2: Numbers and Operators

Loop structures and booleans

Excel Basics: Working with Spreadsheets

CS 3 Midterm 1 Review

Computer Programming. Basic Control Flow - Loops. Adapted from C++ for Everyone and Big C++ by Cay Horstmann, John Wiley & Sons

Note. The above image and many others are courtesy of - this is a wonderful resource for designing circuits.

DESIGN YOUR OWN BUSINESS CARDS

Data Structures and Algorithms Dr. Naveen Garg Department of Computer Science and Engineering Indian Institute of Technology, Delhi.

6.001 Notes: Section 17.5

NAME EET 2259 Lab 3 The Boolean Data Type

Recursively Enumerable Languages, Turing Machines, and Decidability

A simple problem that has a solution that is far deeper than expected!

Using Microsoft Excel

How to approach a computational problem

CS125 : Introduction to Computer Science. Lecture Notes #4 Type Checking, Input/Output, and Programming Style

Excerpt from "Art of Problem Solving Volume 1: the Basics" 2014 AoPS Inc.

1.7 Limit of a Function

Foundations, Reasoning About Algorithms, and Design By Contract CMPSC 122

Outlook is easier to use than you might think; it also does a lot more than. Fundamental Features: How Did You Ever Do without Outlook?

Adding content to your Blackboard 9.1 class

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

CSE 341, Autumn 2015, Ruby Introduction Summary


Statistics Case Study 2000 M. J. Clancy and M. C. Linn

Lecture 16 CSE July 1992

Racket. CSE341: Programming Languages Lecture 14 Introduction to Racket. Getting started. Racket vs. Scheme. Example.

12 Macros. Localmake. is an abbreviation for the two instructions. localmake "fred 87. local "fred make "fred 87

Python allows variables to hold string values, just like any other type (Boolean, int, float). So, the following assignment statements are valid:

5 R1 The one green in the same place so either of these could be green.

Chapter01.fm Page 1 Monday, August 23, :52 PM. Part I of Change. The Mechanics. of Change

CS1 Lecture 3 Jan. 22, 2018

4. Java Project Design, Input Methods

Applied Calculus. Lab 1: An Introduction to R

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

CS 115 Data Types and Arithmetic; Testing. Taken from notes by Dr. Neil Moore

This book is about using Visual Basic for Applications (VBA), which is a

My First iphone App. 1. Tutorial Overview

Working with recursion. From definition to template. Readings: HtDP, sections 11, 12, 13 (Intermezzo 2).

Working with recursion

Problem Solving for Intro to Computer Science

LOOPS. Repetition using the while statement

CMSC 201 Fall 2016 Lab 09 Advanced Debugging

9.2 Linux Essentials Exam Objectives

Transcription:

Chapter 29 Input, output, and sequence For this chapter, switch languages in DrRacket to Advanced Student Language. In the real world, we don t usually give a computer all the information it needs, all at once, and then ask it to go off and produce an answer. More often, we start a program and engage in a dialogue with it. For example, a word-processing program shows us the current state of the document; we tell it to add, delete, or move some more words, the program shows us the result, we request some more changes, and so on. We ve seen some ways to interact with a computer program through animations and event handlers, and in this chapter we ll see another (more old-fashioned, but still useful) approach to interaction. In an animation, the program typically goes on running all the time, but responds whenever we move or click the mouse, type a key, etc. In some problems, however, the program can t go on until it gets some information from the user. A familiar (if unpleasant) example are the dialogue boxes that pop up on your screen saying basically something went wrong; should I try again, or give up? Here s another example. Suppose you were a mathematician who wanted a list of prime numbers. Of course, there are infinitely many prime numbers, so if you wrote a program to produce a list of all of them, it would never finish and you would never see any results at all. A more useful approach would be for the program to show you a prime number, then another, then another, and so on until you told it to stop. Even a program that will eventually stop may need to show you some information along the way, then do some more computation, show you some more information, and so on. Of course, you can do this with an animation, but that seems like overkill for information that s basically textual. 427

428 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE But first, we ll introduce another data type, which has actually been available to us all along, but we haven t needed it until this chapter. 29.1 The symbol data type Racket has a built-in type called symbol which behaves, in some ways, like string. The most obvious difference is the spelling rules: a symbol literal starts with an apostrophe and does not end with an apostrophe, but rather at the next space, parenthesis, etc. As a result, a symbol literal cannot contain spaces, parentheses, and certain other punctuation marks. Indeed, the spelling rules for symbol literals are basically the same as those for variable names and function names, except for the apostrophe at the beginning. (You ve actually seen these before: the first argument to error is normally the name of the function that found the problem, as a symbol.) Like image literals, string literals, number literals, and boolean literals, a symbol literal evaluates to itself; it doesn t stand for anything else: (check-expect blah blah) (check-expect this-is-a-long-name this-is-a-long-name) The most common operation on symbols is to test whether two of them are equal, using the symbol=? function, which works analogously to the string=? function: (check-expect (symbol=? blah snark) false) (check-expect (symbol=? blah blah) true) (define author Bloch) (check-expect (symbol=? author Hemingway) false) (check-expect (symbol=? author Bloch) true) And as with all the other types we ve seen, there s a built-in function to test whether something is a symbol, named (not surprisingly) symbol?. It works exactly as you would expect, by analogy with number?, image?, posn?, etc. Unlike strings, symbols are not thought of as made up of individual characters strung together. A symbol is atomic, in the original sense of that word as meaning not made up of smaller parts. So there is no symbol-length or symbol-append function analogous to string-length and string-append. And symbols have no ordering, so there s nothing analogous to string<? and its friends: two symbols are either the same or different, and that s all you can say about them. In exchange for these restrictions, computations on symbols are typically a little faster than those on strings. However, this by itself wouldn t be enough reason to introduce them in this course. I m mentioning them here because the built-in input and output functions treat symbols a little differently from strings. Exercise 29.1.1 Modify the choose-picture function of Exercise 15.3.1 so it takes in a symbol rather than a string as its parameter, e.g. baseball, basketball, Monopoly. Incidentally, the image functions that take in a color name (circle, rectangle, triangle, etc.) also accept the corresponding symbols: red, orange, purple, black, etc.. Exercise 29.1.2 Develop a function named random-color that takes in a dummy argument and ignores it, but returns one of the symbols red, orange, yellow, green, blue, purple chosen at random.

29.2. CONSOLE OUTPUT 429 Exercise 29.1.3 Develop a function named different-color that takes in a color name as a symbol, and returns a different color name, also as a symbol. Which input color goes with which output color is up to you, as long as the result is always different from the input. Hint: DrRacket knows a lot of color names. You could try to write a cond with dozens or hundreds of cases, but that would be horrible, and it would no longer work if somebody added one more color name to Racket. Instead, think about how you can satisfy the requirements of the problem without knowing all the possible colors. Exercise 29.1.4 Modify exercise 17.1.1 so it uses symbols rather than strings as the model. 29.2 Console output Racket has a built-in function named display that does simple textual output. ; display : object -> nothing, but displays the object. Practice Exercise 29.2.1 Try typing each of the following lines in the Interactions pane: (display 5) (display "this is a string") (display this-is-a-symbol) (display (make-posn 3 4)) (display (list "a" "b" "c")) (display (triangle 20 "solid" "blue")) SIDEBAR: Another built-in function, write, acts like display, but shows strings with doublequotes around them, so you can easily tell the difference between a string and a symbol. So far this doesn t look very exciting. If anything, it s less useful than what we ve been doing up until now, because you can t use the result of display in another expression: (+ 1 (display 2)) produces an error message because display doesn t return anything. The display function becomes much more useful if we build something for it to display from smaller pieces. For example, Worked Exercise 29.2.2 Develop a function display-with-label that takes in a string (the label ) and an object, and prints the string followed by the object. Solution: The contract is ; display-with-label : string object -> nothing ; Prints the string and the object.

430 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE A more-or-less realistic test case is (define my-age 46) (display-with-label "Age: " my-age) "should print" "Age: 46" Make up some more test cases. The skeleton and inventory are straightforward: (define (display-with-label label thing) ; label a string ; thing an object of some kind... ) We could easily display just the label, or just the thing (since display takes in any data type), but how can we combine them? Recall the format function (first mentioned in Chapter 19), which is designed to build complex strings from a template with values filled in in various places, returning a string. Conveniently enough, each of the values to fill in can be of almost any data type. So we could try (define (display-with-label label thing) ; label a string ; thing an object of some kind (display (format "~s~s" label thing)) ) Try this on the example above, and it prints "Age: "46 Not bad, but the quotation marks are annoying. Fortunately, format has different formatting codes : s shows strings with their quotation marks, and a shows strings without their quotation marks. (The main reason to use s is to allow the user to tell the difference between strings and symbols.) So (define (display-with-label label thing) ; label a string ; thing an object of some kind (display (format "~a~a" label thing)) ) produces a better result: Age: 46 This combination of format and display is common enough that Racket has a builtin function to do it: the printf function acts just like calling display on the result of format, so we could write the definition more briefly as (define (display-with-label label thing) ; label a string ; thing an object of some kind (printf "~a~a" label thing) )

29.2. CONSOLE OUTPUT 431 SIDEBAR: The display and write functions can indeed take in just about any data type, including images. However, format s job is to build a string, and strings cannot contain images, so if you try format on an image, you ll get weird results. Testing functions that use console output How can we write test cases for a function like display-with-label that uses display or write? check-expect looks at the result returned by a function, but display and write don t return anything! In Exercise 29.2.2, we used the should be approach. But as we already know, automated testing using check-expect is much more convenient. If only we could find out what the function printed, and compare it with a known right answer... As it happens, there s a built-in function named with-output-to-string to do this: it evaluates an expression of your choice (presumably containing display or write), but captures whatever that expression tries to write, and puts it into a string instead; you can then check whether this string is what you expected with check-expect. Its contract may seem a little strange at first: ; with-output-to-string : (nothing -> anything) -> string That is, you give it a function of no parameters; it calls this function, throws away any result it produces, and returns a string constructed from whatever the function displayed. Worked Exercise 29.2.3 Write automated test cases for Exercise 29.2.2. Solution: We need a function of no arguments to pass into with-output-to-string. We could write one for each test case: (define age 46) (define last-name "Bloch") (define (test-case-1) (display-with-label "Age: " age)) (define (test-case-2) (display-with-label "Name: " last-name)) (check-expect (with-output-to-string test-case-1) "Age: 46") (check-expect (with-output-to-string test-case-2) "Name: Bloch") This seems silly. We can define the functions more simply using lambda: (define age 46) (define last-name "Bloch") (check-expect (with-output-to-string (lambda () (display-with-label "Age:" age))) "Age: 46") (check-expect (with-output-to-string (lambda () (display-with-label "Name: " last-name))) "Name: Bloch")

432 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE Functions of no arguments can be thought of as a way to pass around expressions without evaluating them until later. They come up often enough in Racket that they have a special name: they re called thunks. Exercise 29.2.4 Recall the struct definition ; An employee has a string (name) and two numbers (id and salary). (define-struct employee [name id salary]) Develop a function print-employee that takes in an employee and returns nothing, but prints out the information about the employee, nicely formatted. For example, (print-employee (make-employee "Joe" 17 54000)) "should print" "Joe, employee #17, earns $54000/year" 29.3 Sequential programming When you evaluate an expression like (+ (* 3 4) (* 5 6)), Racket needs to compute both 3 4 and5 6, then addthem. It doesn t really matter which of the two multiplications it does first, as long as it knows both answers before it tries to add them. But display and write don t produce answers, they produce side effects, and it matters very much which of two display expressions happens first. Racket has a syntax rule to specify doing things in a particular order: Syntax Rule 10 (begin expr1 expr2...exprn) is an expression. To evaluate it, DrRacket evaluates each of the exprs in order, throwing away any results they produce except the last one, which it returns. For example, type the following into the Interactions pane: (define result (begin (display (+ 12 5)) (* 5 3))) result It prints out the number 17, but gives result the value 15. Now let s try that in the opposite order: (define other-result (begin (* 5 3)) (display (+ 12 5))) other-result This still prints out the number 17, but other-result has no value at all (because display doesn t return anything). The result of (* 5 3) has been thrown away completely. Worked Exercise 29.3.1 Rewrite the function display-with-label to use begin instead of format. Solution: The contract, test cases, skeleton, and inventory are exactly as before. In the function body, clearly, we need to display both the label and the object:

29.3. SEQUENTIAL PROGRAMMING 433 (define (display-with-label label thing)... (display label)... (display thing)...) More specifically, we want to display the label first, followed by the thing. To do this, we ll use begin: (define (display-with-label label thing) (begin (display label) (display thing) )) Controlling lines Sometimes you need to specify that the output should be on more than one line. There are several ways to do this: Use the built-in function ; newline : nothing -> nothing ; advances the display to the next line in between displays in a begin, e.g. > (begin (display "abc") (newline) (display "def")) abc def Hit ENTER in the middle of a quoted string, e.g. > (display "abc def") abc def Some languages don t allow you to do this, so they use a third approach instead: you can put the special character \n in the middle of a quoted string to indicate a new line : > (display "abc\ndef") abc def Notice that all three produced the exact same output; which one you use is largely a matter of personal taste.

434 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE Worked Exercise 29.3.2 Modify the print-employee function to display its information on three separate lines, e.g. Joe Employee #17 $54000/year Solution: The contract, skeleton, and inventory are unchanged, but we ll need to modify the test cases. Here are two versions; either one should work. (check-expect (with-output-to-string (lambda () (print-employee (make-employee "Joe" 17 54000)))) "Joe\nEmployee #17\n$54000/year") (check-expect (with-output-to-string (lambda () (print-employee (make-employee "Joe" 17 54000)))) "Joe Employee #17 $54000/year") Next, we ll need to modify the function body. This can be done in any of several ways: (begin (display (employee-name emp)) (newline) (display "Employee #") (display (employee-id emp)) (newline) (display "$") (display (employee-salary emp)) (display "/year")) (begin (display (employee-name emp)) (display " Employee #") (display (employee-id emp)) (display " $") (display (employee-salary emp)) (display "/year")) (begin (display (employee-name emp)) (display "\nemployee #") (display (employee-id emp)) (display "\n$") (display (employee-salary emp)) (display "/year"))

29.3. SEQUENTIAL PROGRAMMING 435 (printf "~a Employee #~a ~a/year" (employee-name emp) (employee-id emp) (employee-salary emp)) (printf "~a\nemployee #~a\n~a/year" (employee-name emp) (employee-id emp) (employee-salary emp)) Any of these five solutions should work; which one you use is largely a matter of personal taste. Exercise 29.3.3 Develop a function try that takes in a string (function-name), a function of one argument, and a value for that argument. It should print that it is about to call the function name on the specified argument, then call the function, then print that it has returned from the function and what the result was, and finally return that result. For example, (try "cube" cube 5) should print out About to call (cube 5) Returned from (cube 5) with result 125 and finally return the result 125. For another example, (try "display" display "blah") should print out About to call (display "blah") blah Returned from (display "blah") with result Exercise 29.3.4 Develop a function count-down-display that takes in a whole number. It doesn t return anything, but displays the numbers from that number down to 0, one on each line, with blastoff! in place of the number 0. For example, > (count-down-display 5) 5 4 3 2 1 blastoff!

436 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE Exercise 29.3.5 Modify exercise 21.7.10 by adding two buttons, labelled save and load. If the user clicks the save button, the current image (not including the color palette, save and load buttons) will be stored in the file current.png with save-image; the image on the screen shouldn t change. If the user clicks the load button, the image on the screen should be replaced with the contents of current.png (although the color palette, save and load buttons should be unaffected). 29.4 Console input 29.4.1 The read function The opposite of display, in a sense, is the built-in function read. ; read : nothing -> object ; waits for the user to type an expression, and returns it Try typing (read) into the Interactions pane. You should see a box with a typing cursor in it. Type a number like 17 into the box, and hit ENTER; the read function will return 17. Type (read) again, and type a quoted string like "hello there" (complete with the quotation marks) into the box; read will return that string. What happens when you type (read) and type a couple of words like this is a test (without quotation marks) into the box? What happens when you type (read) and type a parenthesized expression like (+ 3 4) into the box? What about (+ 3 (* 4 5))? What happens when you type (read) and type a Boolean literal (true or false) into the box? What happens when you type(read) and type a comment like; this is a comment into the box? What happens when you type (read) and type a symbol like snark (with its apostrophe) into the box? SIDEBAR: This last example should come out looking similar to a function call, but with the function being named quote. In fact, there is a quote function; play with it to find out what it does, then look it up in the Help Desk. There s also a function read-line which reads a whole line of input as a single string, even if it has spaces, parentheses, etc. inside it. Try it. 29.4.2 Testing functions that use console input It s harder to write test cases for a function that involves input: some information may be provided as arguments, but some will be provided as input. So we could write, essentially, an actor s script: I ll say this, the program should say that, I ll say something else, the program should reply with such-and-such. But that s even more of a pain than using should be. So there s a built-in function ; with-input-from-string : string (nothing -> anything) -> anything

29.4. CONSOLE INPUT 437 which calls the specified thunk, but any time it tries to read from the console, it actually gets input from the string instead. with-input-from-string returns whatever the thunk returns. Worked Exercise 29.4.1 Develop a function ask that takes in a string, prints it, waits for input, and returns that input. Solution: Contract: ; ask : string -> object ; prints the string, waits for input, and returns it Test cases, written as an actor s script : (ask "What is your name?) ; It prints "What is your name?". ; I type "Stephen" (without the quotation marks). ; It returns the symbol Stephen. (define age (ask "How old are you?")) ; It prints "How old are you?". ; I type 46. ; It defines age to be 46. Test cases, written using check-expect and with-input-from-string: (check-expect (with-input-from-string "Stephen" (lambda () (ask "What is your name?"))) Stephen) (define age (with-input-from-string "46" (lambda () (ask "How old are you?")))) (check-expect age 46) Definition: (define (ask question) (begin (display question) (read))) Remember that begin always returns the value of its last expression, which in this case is whatever read returns, which is whatever the user typed. Note: Even after your function has passed all its automated tests, it s probably a good idea to try a few tests in the Interactions pane, to make sure your program interacts with the user the way you want it to. Worked Exercise 29.4.2 Develop a function greet-by-name that takes no parameters, asks for your name, then displays Hello, your-name-here!. Solution: Since this function takes keyboard input and also prints to the screen, we ll need both with-input-from-string and with-output-to-string:

438 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE (check-expect (with-output-to-string (lambda () (with-input-from-string "Steve" greet-by-name))) "What s your name?hello, Steve!") This works, but it s a bit of a pain. The with-io-strings function combines the jobs of with-input-from-string and with-output-to-string; its contract is ; with-io-strings: string thunk -> string For example, the above test case could be rewritten as (check-expect (with-io-strings "Steve" greet-by-name) "What s your name?hello, Steve!") I leave the rest of the definition as an exercise for the reader (and it s in the Help Desk documentation for with-io-strings). 29.4.3 Exercises Exercise 29.4.3 Develop a function repeat-input that takes in a string (the question ). It prints the question, waits for input, then prints the result twice, on separate lines, and returns nothing. Hint: You need to read only once, but use the result twice, so you ll need either a helper function or a local. Exercise 29.4.4 Develop a function ask-posn that takes in no arguments, asks the user for an x coordinate and a y coordinate, and creates and returns a posn with those coordinates. Hint: This one does not require local. Exercise 29.4.5 Modify exercise 29.3.5 so that when the user clicks the load or save button, the program asks you for a filename (using ask or something similar), then loads or saves that file rather than always using current.png. You ve now written a simple graphics editor. An optional nice feature would be to have load, save, load from, and save to buttons: load from and save to should behave as above, but load and save will operate on the last filename you used. Hint: You may want to use read-line rather than read, to avoid worrying about whether the input is treated as a symbol or a string, and to allow filenames to contain spaces. 29.5 Input streams Many programs need to operate on a variable amount of information. We ve seen how to do this with lists, but what if the information isn t provided in the form of a completed list?

29.5. INPUT STREAMS 439 Throughout this book, we ve designed functions to correspond to the data type they take in. To handle a sequence of data coming from input, we ll need to describe it as a data type an input stream. We ve been using read to read information from the keyboard. But computer programs often read from files too: word processing documents, spreadsheets, image and music files, etc. Such files feel like lists: they re either empty or they have a sequence of finitely many objects. As you know, the end of a list is indicated by a special object named empty, which is recognized by the empty? function; similarly, the end of a file is indicated by a special object named eof, which is recognized by the eof-object? function. While practicing with the read function, you may have noticed an eof button next to the input box. Clicking this button causes read to return an eof object, as though at the end of a file. (You ll also get an eof object if you read past the end of the string in with-input-from-string.) The read function, in essence, returns the first object, or eof, from an input stream, and has the side effect of advancing the input stream so that the next call to read will return the next object in the stream. As a result, if we want to use the result more than once, we ll need to store it in a local variable. We can now write a function template for functions that operate on input streams. # (define (function-on-input-stream) (local [(define obj (read))] (cond [(eof-object? obj)...] [else ; obj non-eof object ; (function-on-input-stream) whatever this returns... ))) #

440 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE Worked Exercise 29.5.1 Develop a function add-from-input which asks the user for a sequence of numbers, one at a time, terminated by eof, and returns their sum. Solution: The function takes no parameters, but reads from input and returns a number. ; add-from-input : nothing -> number ; (reads zero or more numbers from input, terminated by eof) We ll need several test cases. As with lists, we ll need an empty test case, and a oneelement test case, and a more complicated test case. The function assumes that the inputs are numbers, so we don t need test cases with non-numbers. First, I ll write them in the form of an actor s script : (add-from-input) ; It asks for a number. ; I hit the EOF button. ; It should return 0. (add-from-input) ; It asks for a number. ; I type 7. ; It asks for a number. ; I hit the EOF. ; It should return 7. (add-from-input) ; It asks for a number; I type 7. ; It asks for a number; I type -3. ; It asks for a number; I type 6. ; It asks for a number; I hit EOF. ; It should return 10.

29.5. INPUT STREAMS 441 But it s easier to run the test cases if we automate them with check-expect. Conveniently, add-from-input is already a thunk, so we don t need to wrap it up in a lambda: (check-expect (with-input-from-string "" add-from-input) 0) (check-expect (with-input-from-string "7" add-from-input) 7) (check-expect (with-input-from-string "7-3 6" add-from-input) 10) The template gives us a good deal of the definition: (define ( add-from-input) (local [(define obj (read))] (cond [(eof-object? obj) 0] [else ; obj number ; (add-from-input) number... ))) But this doesn t actually ask for numbers; to do this, let s replace the call to read with a call to ask. The only other thing left to do is add the two numbers: (define (add-from-input) (local [(define obj (ask "Next number?"))] (cond [(eof-object? obj) 0] [else ; obj number ; (add-from-input) number (+ obj (add-from-input)) ))) If we want to make the function more idiotproof, we can change the contract to read a sequence of objects rather than numbers, and have the function signal an error in that case. (check-error (with-input-from-string "7 eight 9" add-from-input) "add-from-input: That s not a number!")... (define (add-from-input) (local [(define obj (ask "Next number?"))] (cond [(eof-object? obj) 0] [(number? obj) (+ obj (add-from-input)) [else (error add-from-input "That s not a number!") )))

442 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE Exercise 29.5.2 Develop a function read-objects which asks the user for a sequence of objects, terminated by eof, and returns a list of those objects, in the order that they were typed in. Exercise 29.5.3 Develop a function read-objects-until which takes in an object (which we ll call the terminator ) and acts just like read-objects above except that it stops when it gets either the eof object or the terminator. For example, suppose I type (read-objects-until quit). It asks me for an object; I type 3. It asks me for an object; I type snark. It asks me for an object; I type quit. It returns the list (list 3 snark). Hint: Since you don t know what type the terminator object will be, you ll need equal?. Exercise 29.5.4 Develop a function echo which asks the user for a sequence of objects, terminated by eof, and displays each of them on a separate line, in the same order that they were typed in. Hint: You ll need begin. 29.6 Files In the real world, programs read and write files at least as often as they read from the keyboard or write to the screen. There are predefined functions to make that easy: ; with-input-from-file : string(filename) thunk -> anything ; Calls the thunk in such a way that if the thunk uses read or ; similar functions, it will read from the specified file instead ; of from the keyboard. ; Returns the result of the thunk. ; with-output-to-file : string(filename) thunk -> anything ; Calls the thunk in such a way that if the thunk uses display, ; write, print, printf, etc., they will write to the specified file ; instead of to the screen. Note: if you plan to write from a program into a file, and later read from the same file into a program, it s a good idea to use write rather than display; otherwise you may write out a string and read it in as a symbol. Also, write and display do a good job of showing images on the screen, but they don t know how to save an image to a file; if you need to store images in files, use save-image and bitmap instead.

29.7. THE WORLD WIDE WEB 443 Exercise 29.6.1 Modify exercise 21.7.9 to add save and load buttons as in exercise 29.3.5, and optionally save-to and load-from buttons as in exercise 29.4.5. Note that when you save to a file and re-load later from the same file, the cursor position (as well as the contents) should be preserved. You ve now written a very simple word processor. 29.7 The World Wide Web Another common source of information to programs is the World Wide Web. There s a predefined function that helps you get information from Web sites: ; with-input-from-url : string thunk -> anything ; Calls the thunk in such a way that if it uses read or similar functions, ; they ll read from the specified Web page instead of from the keyboard. For example, (with-input-from-url "http://www.google.com" read-line) will give you back the first line of the Google website (headers, HTML, Javascript, the whole works). Of course, extracting really useful information from the Web requires recognizing the structure of an HTML or XML document. DrRacket comes with libraries to help with that, but they re beyond the scope of this book; look up XML in the Help Desk. 29.8 Review of important words and concepts Historically, most programs have expected to read their input, either from a file or from the user s keyboard, and write their results, either to a file or in text form to the user s screen. In this chapter we ve learned how to do that in (Advanced Student Language) Racket. These are our first examples of functions with side effects (almost: define and define-struct can be thought of as functions with side effects), and hence the first for which the order of calling functions makes a big difference. To tell Racket that we want to evaluate a series of expressions in order, not for their values but for their side effects, we use the begin form.

444 CHAPTER 29. INPUT, OUTPUT, AND SEQUENCE 29.9 Reference: input, output, and sequence In this chapter, we ve seen the following new built-in functions: display write printf begin newline read read-line with-input-from-string with-output-to-string with-io-strings with-input-from-file with-output-to-file with-input-from-url