Intermezzo: BSL
Thus far we have approached teaching BSL as if it were a natural language. Like toddlers, we first taught you the vocabulary of the language with an intuitive understanding of its meaning. Next we exposed you to some basic rules of how to compose and not to compose sentences. Truly effective communication, however, requires some formal study of a language’s vocabulary, grammar, and meaning.
A programming language is in many ways like a natural language. It has a vocabulary and a grammar. The vocabulary is the collection of those words from which we compose sentences in our language. A sentence in a programming language is an expression or a function definition; the language’s grammar dictates how to form complete sentences from words. Programmers use the word syntax to refer to the basic vocabularies and grammars of programming languages.
Not all grammatical sentences are meaningful—
The intermezzos of this book introduce ideas from programming languages that programmers must eventually understand and appreciate but are secondary to program design. In this intermezzo, we discuss the meaning of BSL programs as if it were an extension of the familiar laws of arithmetic and algebra. After all, computation starts with this form of simple mathematics, and we should understand the connection between this mathematics and computing. The first three sections present the vocabulary, grammar, and meaning of a good portion of BSL. Based on this new understanding of BSL, the fourth resumes our discussion of errors. The remaining three sections revisit and and or expressions, constant definitions, and structure types.
BSL: Vocabulary
Figure 27 introduces and defines BSL’s basic vocabulary. It consists of names that may or may not have meaning according to BSL and of constants, also known as values and pieces of data.
An name or a variable is a sequence of characters not including a space or one of the following: " , ' ` ( ) [ ] { } | ; #:A value, also a called a piece of data, is one of:
A number is one of: 1, -1, 3/5, 1.22, 1.22, 0+1i, and so on. The syntax for BSL numbers is complicated because it accommodates a range of formats: positive and negative numbers, fractions and decimal numbers, exact and inexact numbers, real and complex numbers, numbers in bases other than 10, and more. Understanding the precise notation for numbers requires a thorough understanding of grammars and parsing, which is out of scope for this intermezzo.
A boolean is one of: #t or #f.
A string is one of: "", "a", "doll", "he says \"hello world\" ok", and so on. In general, it is a sequence of characters enclosed by a pair of ". For example, are all strings.
An image is a png, jpg, tiff, and various other formats. We intentionally omit a precise definition.
We use v, v-1, v-2 and the like when we wish to say “any possible value.”
Each of the explanations defines a set via a suggestive iteration of its elements. Although it is possible to specify these collections in their entirety and in a formal manner, we consider this superfluous here and trust in your intuition. Keep in mind that each of these sets may come with some extra elements.
BSL: Grammar
def-or-expr def-or-expr
(define (variable variable) expr)
(define (variable variable variable) expr)
(define (variable variable variable variable) expr)
program = def-or-expr ... def-or-expr = definition | expr definition = (define (variable variable variable ...) expr) expr = variable | value | (primitive expr expr ...) | (variable expr expr ...) | (cond [expr expr] ... [expr expr]) | (cond [expr expr] ... [else expr])
The final point about grammars concerns the three “words” that come in a distinct font: define, cond, and else. According to the definition of BSL vocabulary, these three words are names. What the vocabulary definition does not tell us is that these names have a pre-defined meaning. In BSL, these words serve as markers that differentiate some compound sentences from others, and in acknowledgment of their role, such words are called keywords.
The first syntactic category says that a program is a def-or-expr.In DrRacket, a program really consists of two distinct parts: the definitions area and the expressions in the interactions area. Expressions may refer to the definitions.
The second definition tells us that a def-or-expr is either a definition or an expr.
The last definition lists all ways of forming an expr, and the second one is value.
The interesting parts of the grammar show how to form compound sentences, which are sentences built from other sentences. For example, the definition part tells us that a function definition is formed by using “(”, followed by the keyword define, followed by another “(”, followed by a sequence of at least two variables, followed by “)”, followed by an expr, and closed by a right parenthesis “)” that matches the very first one. You can see from this example how the leading keyword define distinguishes definitions from expressions.
Expressions, called expr, come in six flavors: variables, constants, primitive applications, (function) applications, and two varieties of conditionals. While the first two are atomic sentences, the last four are compound sentences. Note how the keyword cond distinguishes conditional expressions from primitive and function applications.
Here are three examples of expressions: "all", x, and (f x). The first one belongs to the class of strings and is therefore an expression. The second is a variable, and every variable is an expression. The third is a function application, because f and x are variables.
In contrast, the following parenthesized sentences are not expressions: (f define), (cond x), and ((f 2) 10). The first one partially matches the shape of a function application but it uses define as if it were a variable. The second one fails to be a correct cond expression because it contains a variable as the second item and not a pair of expressions surrounded by parentheses. The last one is neither a conditional nor an application because the first part is an expression.
Finally, you may notice that the grammar does not mention white space: blank spaces, tabs, and newlines.Keep in mind that two kinds of readers study your BSL programs: people and DrRacket. BSL is a permissive language. As long as there is some white space between the elements of any sequence in a program, DrRacket can understand your BSL programs. Good programmers, however, may not like what you write. These programmers use white space to make their programs easily readable. Most importantly, they adopt a style that favors human readers over the software applications that process programs (such as DrRacket). They pick up this style from careful reading code examples in books, paying attention to how it is formatted.
Explain why the sentences are legal or illegal. Determine whether they belong the category expr or definition.
Note on Grammatical Terminology: The components of compound sentences have names. We have introduced some of these names on an informal basis. Figure 29 provides a summary of the conventions.
; function application: (function argument ... argument) ; function definition: (define (function-name parameter ... parameter) function-body) ; conditional expression: (cond cond-clause ... cond-clause) ; cond clause [condition answer]
In addition to the terminology of figure 29, we say function header for second component of a definition. Accordingly, the expression component is called function body. People who consider programming languages as a form of mathematics use left-hand side for a header and right-hand side for the body.
On occasion, you also hear or read the term actual arguments for the arguments in a function application. People tend to use this terminology when they think of the value of the arguments, which they also called their meaning.
BSL: Meaning
When DrRacket evaluates an expression, it uses nothing but the laws of
arithmetic and algebra to convert an expression into a value—
(boolean? (= (string-length (string-append "hello" "world")) (+ 1 3))) == (boolean? (= (string-length (string-append "hello" "world")) 4)) == (boolean? (= (string-length "helloworld") 4)) == (boolean? (= 10 4)) == (boolean? false) == true
(f v-1 ... v-n) == f-body ; with all occurrences of x-1... x-n ; replaced with v-1 ... v-n, respectively
== |
(cond [(zero? 3) 1] [(= 3 3) (+ 1 1)] [else 3]) == ; by plain arithmetic and “equals for equals” (cond [false 1] [(= 3 3) (+ 1 1)] [else 3]) == ; by rule condfalse (cond [(= 3 3) (+ 1 1)] [else 3]) == ; by plain arithmetic and “equals for equals” (cond [true (+ 1 1)] [else 3]) == ; by rule condtrue (+ 1 1)
Show how DrRacket evaluates the following expressions, step by step:
BSL: Errors
When DrRacket discovers that some parenthesized phrase does not belong to BSL, it signals a syntax error. To determine whether a fully-parenthesized program is syntactically legal, DrRacket uses the grammar in figure 28 and reasons along the lines explained above. Not all syntactically legal programs have meaning, however.
> (/ 1 0) /: division by zero
Simplify the outermost and left-most subexpression that is ready for evaluation.
(define (checked-area-of-disk v) (cond [(number? v) (area-of-disk v)] [else (error "number expected")]))
(- (checked-area-of-disk "a") (checked-area-of-disk 10)) == (- (cond [(number? "a") (area-of-disk "a")] [else (error "number expected")]) (checked-area-of-disk 10)) == (- (cond [false (area-of-disk "a")] [else (error "number expected")]) (checked-area-of-disk 10)) == (- (error "number expected") (checked-area-of-disk 10))
== (error "number expected")
Boolean Expressions
Our current definition of the Beginning Student BSL language omits two forms of expressions: and and or expressions. Adding them provides a case study of how to study new language constructs. We must first understand their syntax and then their semantics.
exp-2
Exercise 113. The use of if may have surprised you in another way because this intermezzo does not mention this form elsewhere. In short, the intermezzo appears to explain and with a form that has no explanation either. At this point, we are relying on your intuitive understanding of if as a short-hand for cond. Write down a rule that shows how to reformulate(if exp-test exp-then exp-else)
as a cond expression.
Constant Definitions
definition | = | ... | ||
| | (define name expr) |
(define RADIUS 5)
(define RADIUS 10) (define DIAMETER (* 2 RADIUS)) (define (area r) (* 3.14 (* r r))) (define AREA-OF-RADIUS (area RADIUS))
(define RADIUS 10) (define DIAMETER (* 2 RADIUS)) (define AREA-OF-RADIUS (area RADIUS)) (define (area r) (* 3.14 (* r r)))
Does the evaluation of the following program signal an error?
(define COLD-F 32) (define COLD-C (fahrenheit->celsius COLD-F)) (define (fahrenheit->celsius f) (* 5/9 (- f 32))) How about the next one?
Structure Type Definitions
definition | = | ... | ||
| | (define-struct name (name ...)) |
(define-struct point (x y z))
(define-struct (point x y z)) (define-struct point x y z)
(define-struct c (s-1 ... s-n))
make-c: a constructor;
c-s-1... c-s-n: a series of selectors; and
c?: a predicate.
A value, also a called a piece of data, is one of: a number, a boolean, a string, an image,
or a structure value:
(make-c _value-1 ... _value-n) assuming a structure type definition for c exists and the constructor make-c is available.
(make-point 1 2 -1) (make-point "one" "hello" "world") (make-point 1 "one" (make-point 1 2 -1)) ...
(point-x (make-point V U W)) | == | V |
(point-y (make-point V U W)) | == | U |
(point-z (make-point V U W)) | == | W |
(define-struct oops ())
(define-struct child (parents dob date))
(define-struct (child person) (dob date))
Explain why the sentences are legal or illegal.
(make-point 1 2 3)
(make-point (make-point 1 2 3) 4 5)
(make-point (+ 1 2) 3 4)
Explain why the expressions are values or not.
(define-struct ball (x y speed-x speed-y))
Predict the results of evaluating the following expression:Verify your predictions with DrRacket.
BSL: Tests
Figure 30 collects all the elements of BSL that this intermezzo explains plus the tests: check-expect, check-within, and check-error. The actual grammar of BSL is even a bit larger; see the Help Desk for details.
program = def-or-expr ... def-or-expr = definition | expr | test-case definition = (define (name variable variable ...) expr) | (define name expr) | (define-struct name (name ...)) expr = (name expr expr ...) | (cond [expr expr] ... [expr expr]) | (cond [expr expr] ... [else expr]) | (and expr expr expr ...) | (or expr expr expr ...) | name | number | string | image test-case = (check-expect expr expr) | (check-within expr expr expr) | (check-error expr)
The meaning of testing expressions is easy to explain. When you click the “Run” button DrRacket collects all testing expressions and moves them from the middle of the program to the end, retaining in the order in which they appear. Then it evaluates the definitions, expressions, and tests and allows you to explore additional expressions in the interactions area.
In principle, the evaluation of a test evaluates its pieces and then compares them with an equality predicate, equal? to be precise. Beyond that, tests communicate with DrRacket to collect some success and failure statistics and information on how to display test failures.