Scheme -- Outline of Fundamental Language
Features [by David G. Kay, © 2004]
One of Scheme's strengths is its simplicity.
These few pages describe nearly everything you need to write programs in
Scheme; it would take much longer for other popular languages. Of course
Scheme has features that aren't listed here, but this outline describes
the essentials.
Syntax: The grammar; how you say something.
Semantics: The meaning; what something does.
-
Data
-
Single-valued
-
Numbers: E.g., 0, 175, -23, 5194.345
-
Arithmetic operations: +,
-,
*,
/
-
Other operations: sqrt,
expt,
many more
-
Predicate functions (true/false result): even?,
odd?
-
Relational operations:
=,
<,
<=,
>,
>=
-
Symbols: E.g., Monday,
Tuesday,
red,
green
-
Strings: E.g., "Hello,
there!" For text we plan to print (using
display),
possibly containing spaces or other special characters
-
Booleans: E.g., true
or #t,
false
or #f.
Named for 19th-century British mathematician George Boole.
-
Logical operations: and,
or,
not
-
Multiple-valued
-
Heterogeneous -- related items, possibly of different
types
-
Structures :
(define-struct Rrant (name cuisine phone
dish price))
gives the blueprint for a class (a category) of object.
It automatically creates these functions
-
(make-Rrant "Gino's"
"Pizza" "311-1111" "Combo" 12.95)
creates a Rrant
object, one instance of the Rrant
class.
-
The accessor functions Rrant-name,
Rrant-cuisine,
and so on.
-
Homogeneous -- all items the same type
-
Lists
-
Constructors: operations that build lists
-
cons
-
list
-
append
-
Constants
-
empty
or ()
-
Accessors/Selectors
-
first
-
rest
-
empty?
or null?
-
Vectors (provide better performance in certain situations)
-
Giving names to values
(define Stooges (list "Manny"
"Moe" "Curly"))
-
We need to do this less often in Scheme than in other
languages; often we can just put the expression we need in the place where
we need it.
-
Sometimes we need to define a name temporarily, just
for use within a function. For this we use local
or let.
-
Control
-
Functions
-
Calling a function (invoking a function):
(+ 5 7)
-
Parentheses surrounding every expression (not optional)
-
Prefix operators: When Scheme evaluates an expression,
it takes the first item in the expression as an operator (the verb, the
function) and the remaining items as the operands (the nouns, the inputs
or arguments). It applies the function to its inputs and returns the resulting
value.
-
Did you notice? Scheme expressions are lists! When
programs and data have the same syntactic form, all kinds of interesting
things can happen.
-
Composing functions (combining calls to functions):
Any Scheme expression with the right type of value can be an argument to
a function. The value of (+
3 5) is a number, so we can say (*
10 (+ 3 5)) because *
expects numbers for its arguments.
-
Defining a function
(define double
(lambda (n)
(* 2 n)))
-
The first line, like any define,
associates a name with a value.
-
On the second line, lambda
says "make a function" and next is a list of names for the inputs
(one name, one input; two names, two inputs; and so on). These input names
are called parameters; each argument (input) when we call the fuction
corresponds to one parameter in the function definition. This gives us
names we can use in the function to refer to the inputs (without requiring
that the user of the function know which names we picked; this is useful
in big programs with multiple authors).
-
The remaining lines are the body of the function--an
expression (probably using the names of the input(s)) whose value is what
the function returns when it's called.
-
This alternative form (used in the HtDP text)
is exactly equivalent:
(define (double n)
(* 2 n))
-
Selection: If we want to choose alternative
values based on the answer to some question, we can use cond:
(cond
((< temperature 50) "It's
cold")
((> temperature 90) "It's
hot")
(else "It's okay"))
-
Syntax
-
Each line after cond
is called a "cond clause." Each cond clause is parenthesized
(but square brackets are allowed instead because some programmers feel that
brackets make the code easier to read).
-
Each cond clause has two parts. The first part is
a boolean expression (something whose value is true or false) and the second
part is any Scheme expression.
-
For the last cond clause, the first part can be the
word else.
-
Semantics
-
Scheme looks at each cond clause, in order.
-
If the left part is true, the value of the whole
cond expression is the value of the right part.
-
If the left part is false, Scheme goes on to the
next cond clause.
-
If Scheme reaches the else
clause, it returns the value of the second part of that clause.
-
Repetition: To apply some function to all
the elements on a list (or otherwise to do some task many times automatically),
we usually divide the task into a "base case" (what we need to
do when the list is empty, usually) and a "recursive case" that
processes the first item of the list and then starts the whole task over
with the rest of the list (so that eventually, it reaches the base case).
Sometimes we need more than one base case or more than one recursive case.
; member?: item list -> boolean
; Return true if item occurs on the list,
and false otherwise
(define member?
(lambda (item L)
(cond
((empty? L)
false)
((equal? item
(first L)) true)
(else (member?
item (rest L))))))
-
The first cond clause says, "If the list is
empty, the item can't be on it; return false."
-
The second cond clause says, "If the item we're
looking for matches the first item on the list, then it is a member;
return true."
-
The last cond clause says, "Since the item we're
looking for didn't match the first item on the list, we should return
the answer to this question: 'Is the item a member of the rest
of the list?'."