Lisp application areas:
/cse/courses/misc_lang/axp/mit-scheme-7.3/bin/schemeor to avoid typing all that, add the following line into the file .cshrc in your home directory:
set path = ( $path /cse/courses/misc_lang/axp/mit-scheme-7.3/bin/)so that scheme is on your search path.
Scheme uses a "read-eval-print loop" at the top level: read in an expression, evaluate it, then print the result. control-d exits.
If you get an error, you'll end up in the debugger. For now just type
(restart 1)
To read in the contents of a file named myprog.s, say
(load "myprog.s")See the MIT Scheme User Manual for more about the environment.
(function arg1 arg2 ... argN)Examples:
(+ 2 3) (abs -4) (+ (* 2 3) 8) (+ 3 4 5 1) ;; note that + and * can take an arbitrary number of arguments ;; actually so can - and / but you'll get a headache trying to remember ;; what it means ;; ;; semicolon means the rest of the line is a comment
(x) (elmer fudd) (2 3 5 7 11) (2 3 x y "zoo" 2.9) ()Box-and-arrow representation of lists:
_______________ ________________
| | | | | |
| o | ----|----->| o | o |
|___|___|_______| |____|___|___|___|
| | |
| | |
elmer fudd ()
Or
_______________ _____________
| | | | | / |
| o | ----|----->| o | / |
|___|___|_______| |____|___|/___|
| |
| |
elmer fudd
Notes:
<S-expression> => <return-value>when we want to show an S-expression and the evaluation of that S-expression. For instance:
(+ 2 3) => 5 (cons 1 () ) => (1)Evaluation rules:
(+ 2 3) => 5 (+ (* 3 3) 10) => 19 (equal? 10 (+ 4 6)) => #t
'x => x (list elmer fudd) => error! elmer is unbound symbol (list 'elmer 'fudd) => (elmer fudd) (elmer fudd) => error! elmer is unknown function '(elmer fudd) => (elmer fudd) (equal? (x) (x)) => error! x is unknown function (equal? '(x) '(x)) => #t (cons 'x '(y z)) => (x y z) (cons 'x () ) => (x) (car '(1 2 3)) => 1 (cdr (cons 1 '(2 3))) => (2 3)Note that there are 3 ways to make a list:
'x => x (quote x) => x(Alan Perlis: "syntactic sugar causes cancer of the semicolon".)
This declares a variable called clam (if one doesn't exist) and makes it refer to 17:
(define clam 17) clam => 17 (define clam 23) ; this rebinds clam to 23 (+ clam 1) => 24
(define bert '(a b c)) (define ernie bert)Scheme uses pointers: bert and ernie now both point at the same list.
In 341 we'll only use define to bind global variables, and we won't rebind them once they are bound, except when debugging.
We can also use define to bind variables that are the names of functions:
(define (double x) ; x is local to the function double (* 2 x))This is actually a shorthand for:
(define double (lambda (x) (* 2 x)))where lambda is a way of defining an anonymous function.
;; general form of let
(let ((name1 value1)
(name2 value2)
...
(nameN valueN))
expression1
expression2
...
expressionQ)
;; reverse a list and double it
;; less efficient version:
(define (r2 x)
(append (reverse x) (reverse x)))
;; more efficient version:
(define (r2 x)
(let ((r (reverse x)))
(append r r))
The one problem with Let is that while the bindings are being created,
expressions cannot refer to bindings that have been made previously.
For example, this doesn't work, since x isn't known outside the body:
(let ((x 3)
(y (+ x 1)))
(+ x y))
To get around this problem, Scheme provides us with let*:
(let* ((x 3)
(y (+ x 1)))
(+ x y))
define can be used to
rebind a variable to a new value (but we won't do it,
right?) Scheme also has an assignment statement:
(set! x 42)... which we won't use either. Good scheme style is to avoid using set!, and to program without side effects. Consider carefully whether you really need non-local variables. They are reasonable for constants and of course functions. Use lots of small functions.
Bad style:
(define badbadbad () ) (define (r2 x) (set! badbadbab (reverse x)) (append badbadbad badbadbad))
(define (function-name param1 param2 ... paramk) expr1 expr2 ... exprN)expr1, expr2, ..., exprN are evaluated in order, and Scheme returns the value of exprN. However, since the values of expr1, ... exprN-1 are thrown away, the only reason to do this is if they have side effects. So in 341 we'll write functions with just a single expression in the body.
Some places you might use multiple expressions, though, would be for a bunch of print statements, file operations, etc (which of course have side effects).
(define (double x) (* 2 x)) (double 4) => 8 (define (centigrade-to-fahrenheit c) (+ (* 1.8 c) 32.0)) (centigrade-to-fahrenheit 100.0) => 212.0The x in the double function is the formal parameter. It has scope only within the function. Consider:
(define x 10) (define (add1 x) (+ x 1)) (define (double-add x) (double (add1 x))) (double-add x) => 22 Three different x's here...
Functions can take 0 arguments:
(define (test) 3) (test) => 3
(define clam '(1 2 3)) (define octopus clam) ; clam and octopus refer to the same list (eq? 'clam 'clam) => #t (eq? clam clam) => #t (eq? clam octopus) => #t (eq? clam '(1 2 3)) => #f (or () ) (eq? '(1 2 3) '(1 2 3)) => #f (eq? 10 10) => #t ; (generally, but imp. dependent) (eq? 10.0 10.0) => #f ; (generally, but imp. dependent) (eqv? 10 10) => #t ; always (eqv? 10.0 10.0) => #t ; always (eqv? 10.0 10) =>#f ; no conversion btwn types (equal? clam '(1 2 3)) => #t (equal? '(1 2 3) '(1 2 3)) => #tScheme provides
= for comparing
two numbers, and will coerce one type to another.
For example, (equal? 0 0.0) returns #f, but
(= 0 0.0) returns #t.
(and expr1 expr2 ... expr-n) ; return true if all the expr's are true ; ... or more precisely, return expr-n if all the expr's evaluate to ; something other than #f. Otherwise return #f (and (equal? 2 3) (equal? 2 2) #t) => #f (or expr1 expr2 ... expr-n) ; return true if at least one of the expr's is true ; ... or more precisely, return expr-j if expr-j is the first expr that ; evaluates to something other than #f. Otherwise return #f. (or (equal? 2 3) (equal? 2 2) #t) => #t (or (equal? 2 3) 'fred (equal? 3 (/ 1 0))) => 'fred (define (single-digit x) (and (> x 0) (< x 10))) (not expr) ; return true if expr is false (not (= 10 20)) => #t
Other languages may provide both as built-in functions. For example, in Ada
1=1 OR 3=(1/0) versus 1=1 OR ELSE 3=(1/0)
(if (= 5 (+ 2 3)) 10 20) => 10
(if (= 0 1) (/ 1 0) (+ 2 3)) => 5
; note that the (/ 1 0) is not evaluated
(define (my-max x y)
(if (> x y) x y))
(my-max 10 20) => 20
(define (my-max3 x y z)
(if (and (> x y) (> x z))
x
(if (> y z)
y
z)))
(cond (test1 expr1)
(test2 expr2)
....
(else exprn))
As soon as we find a test that evaluates to true, then we evaluate the
corresponding expr and return its value. The remaining tests are not
evaluated, and all the other expr's are not evaluated.
If none of the tests evaluate to true then we evaluate exprn (the "else"
part) and return its value. (You can leave off the else part but it's not
good style.)
(define (weather f)
(cond ((> f 80) 'too-hot)
((> f 60) 'nice)
((< f 35) 'too-cold)
(else 'typical-seattle)))
(define (cadr s) (car (cdr s)))and gets the second element of a list.
All combinations are defined up to 4 letters, e.g. caddr, cdadar, etc.
(define z 100)
(define (squid w)
(clam w z)) ; w and z are visible here
(define (test x)
(let ((y (* 2 x))) ; x, y, and z are visible inside the body of let
(+ x y z))) ; w is not visible inside here
(define (clam a)
(+ a x)) ; x is not visible here, so this will give an error