Introduction to Scheme http://docs.racket-lang.org/quick/ http://docs.racket-lang.org/teachpack/2htdp2htdp.html http://picturingprograms.com/download/chap03.pdf cs7100(Prasad) L3Scheme
Scheme Meta-language for coding interpreters Scheme = LISP + ALGOL “clean” semantics Scheme = LISP + ALGOL simple uniform syntax; symbols and lists block structure; static scoping expression : evaluated for its value statement : evaluated for its effect Dynamic type checking flexible but inefficient (rapid prototyping) good for dealing with heterogeneous data structures cs7100(Prasad) L3Scheme
Expressions Literals Variables Procedure calls Literals Variables numerals(2), strings(“abc”), boolean(#t), etc. Variables Identifier represents a variable. Variable reference denotes the value of its binding. x ref 5 cs7100(Prasad) L3Scheme
Scheme Identifiers E.g., y,x5,+,two+two,zero?, etc. (Illegal) 5x,y)2,ab c, etc. Identifiers reserved keywords variables pre-defined functions/constants ordinary functions = procedures cs7100(Prasad) L3Scheme
Procedure Call (application) (operator-expr operand-expr ...) prefix expression (proc/op arg1 arg2 arg3 ...) Order of evaluation of the sub-expressions is “explicitly” left unspecified by Scheme. cf. C is silent about it. cf. Java specifies a left to right processing. (+ x (p 2 3)) ((f 2 3) 5 6) cs7100(Prasad) L3Scheme
Special Forms Definition Conditional > (define false #f) (define <var> <expr>) > (define false #f) Conditional (if <test> <then> <else>) > (if (zero? 5) 0 #t) > (if #t 'emptyList 'never) emptyList cs7100(Prasad) L3Scheme
Data Types values, operations, canonical representation Type-checking static : compile-time : efficient dynamic : run-time : flexible numbers: +, -, *, number?, =, etc. booleans: #t, #f, boolean?, etc. strings: string?, string->list, etc. cs7100(Prasad) L3Scheme
Symbols Identifiers treated as primitive values. Primitive operations Distinct from identifiers that name variables in the program text. Distinct from strings (sequence of characters). Primitive operations quote symbol? Facilitates meta-programming cs7100(Prasad) L3Scheme
Lists Ordered sequence of elements of arbitrary type (Heterogeneous) operations car, cdr, cons, null?, ... list, append, ... cadr, caadr, caddr, … (cadar X) = (car (cdr (car X))) cs7100(Prasad) L3Scheme
Examples (cons (quote (a)) (quote (1 2))) => ((a) 1 2) (cons ’(a) ’(1 2)) (list ’(a) ’(1 2) ’((“a”))) => ((a) (1 2) ((“a”))) (append ’(a) ’(1 2) ’((“a”))) => (a 1 2 (“a”)) cs7100(Prasad) L3Scheme
Pairs: Expression, Internal Representation and Print form (cons 'a 'b) (cons 'a (cons 'b '()) ) = (a . b) b a = (a . (b . ()) ) = (a b) Dotted pair notation () a b cs7100(Prasad) L3Scheme
Equivalence : Syntactic vs Semantic (eq? (cons 3 '()) (cons 3 '())) #f (define a (cons 3 '())) (define b (cons 3 '())) (eq? a b) (define c a) (eq? a c) #t Java: == vs .equals Scheme: eq? vs eqv? vs equal? http://people.csail.mit.edu/jaffer/r5rs_8.html#SEC49 (eqv? 'a 'b) ==> #f (eqv? '() '()) ==> #t (eqv? (cons 1 2) (cons 1 2)) ==> #f (let ((p (lambda (x) x))) (eqv? p p)) ==> #t (eqv? (lambda (x) x) (lambda (y) y)) ==> unspecified (eq? '(a) '(a)) ==> unspecified (eq? (list 'a) (list 'a)) ==> #f (eq? '() '()) ==> #t (eq? car car) ==> #t (let ((n (+ 2 3))) (eq? n n)) ==> unspecified (let ((x '(a))) (eq? x x)) ==> #t (equal? (make-vector 5 'a) (make-vector 5 'a)) ==> #t (equal? (lambda (x) x) (lambda (y) y)) ==> unspecified cs7100(Prasad) L3Scheme
Equivalence : Syntactic vs Semantic (equal? (cons 3 '()) (cons 3 '())) #t (equal? (make-vector 5 'a) (make-vector 5 'a)) (equal? (lambda(x)x) (lambda(y)y)) #f Formally unspecified Java: == vs .equals Scheme: eq? vs eqv? vs equal? http://people.csail.mit.edu/jaffer/r5rs_8.html#SEC49 (eqv? 'a 'b) ==> #f (eqv? '() '()) ==> #t (eqv? (cons 1 2) (cons 1 2)) ==> #f (let ((p (lambda (x) x))) (eqv? p p)) ==> #t (eqv? (lambda (x) x) (lambda (y) y)) ==> unspecified (eq? '(a) '(a)) ==> unspecified (eq? (list 'a) (list 'a)) ==> #f (eq? '() '()) ==> #t (eq? car car) ==> #t (let ((n (+ 2 3))) (eq? n n)) ==> unspecified (let ((x '(a))) (eq? x x)) ==> #t (equal? (make-vector 5 'a) (make-vector 5 'a)) ==> #t (equal? (lambda (x) x) (lambda (y) y)) ==> unspecified cs7100(Prasad) L3Scheme
Vectors Both records and arrays provide random access to components. However, records are heterogeneous and provide access to components via field-names, while arrays are homogeneous and provide access to components via computable index. Vectors are heterogeneous structures that provide random access to components using a computable index. cs7100(Prasad) L3Scheme
Constructors and accessors (define v (vector “1” (+ 1 2) )) #( “1” 3 ) (define v (vector “1” ’(+ 1 2) )) #( “1” (+ 1 2) ) (vector-ref v 0) “1” (vector-length v) 2 Index is 0-based. cs7100(Prasad) L3Scheme
Procedures In Scheme, procedures are first-class objects. That is, they may be (i) passed to procedures or (ii) returned from procedures or (iii) stored in a data structure. (procedure? append) #t (if (procedure? 3) car cdr) #<procedure> cs7100(Prasad) L3Scheme
(( (if (procedure? procedure?) car cdr) (cons cdr car) ) '(list append)) = ( (car (cons cdr car)) (cdr '(list append)) '(append) Function values and higher order functions; self-application cs7100(Prasad) L3Scheme
Apply-function (apply cons '( x (y z))) = (cons 'x '(y z)) = (x y z) (apply f '(a1 a2 ... an)) = (f 'a1 'a2 ... 'an) (apply <func> <list-of-args>) Another example HOF: map BENEFIT: (0) Apply as shown enables one to unify functions of different arities. OTHER REAL BENEFITS: (1) writing function application expressions when the actual function value is to be determined at run-time. (2) defining variable-arity functions. cs7100(Prasad) L3Scheme
Apply-function Apply-function is not compelling if the function is of fixed arity and is statically known with its arguments. Apply-function is indispensable for defining variable arity function or for invoking dynamically computed function. Apply-function enables us to unify functions of different arities, and is an important component of an interpreter. Another example HOF: map BENEFIT: (0) Apply as shown enables one to unify functions of different arities. OTHER REAL BENEFITS: (1) writing function application expressions when the actual function value is to be determined at run-time. (2) defining variable-arity functions. cs7100(Prasad) L3Scheme
(apply apply (list procedure? (list apply))) = (apply apply [ proc?-fn [ apply-fn ] ] ) = (apply proc?-fn [apply-fn] ) = (procedure? apply) = #t Programming with functions cs7100(Prasad) L3Scheme
Anonymous Functions (lambda <formals-list> <body-expr>) E.g., ((lambda (n) (+ n 2)) (+ 1 4) ) = 7 Evaluate actual argument expressions Bind these values to corresponding formals in formals-list Evaluate body expression (static scoping) cs7100(Prasad) L3Scheme
Variable Arity Procedures (+ 1 2 3) (append '(1 (p q)) '() '(a b)) (list 1.2 3/4 5) (lambda <formal> <body>) <formal> is bound to the list of actual argument values supplied in a call. cs7100(Prasad) L3Scheme
(define mul (lambda x (if (null? x) 1 (* (car x) (apply mul (cdr x)) ) )) ; 1 is identity w.r.t * ) ; assuming * is binary (mul 2 (+ 2 2) 5) (mul 1 2 3) -> (apply mul ’(2 3)) Without apply, mul will get a list as actual argument. cs7100(Prasad) L3Scheme
Binding constructs in Scheme define binds value to a name. l-function application binds formal parameters to actual argument values. let-constructs introduces local bindings let let* letrec Case-lambda construct enables default arguments but does not seem to be supported by R5RS. (define substring1 (case-lambda [(s) (substring1 s 0 (string-length s))] [(s start) (substring1 s start (string-length s))] [(s start end) (substring s start end)])) cs7100(Prasad) L3Scheme
let-construct ( let ( (var1 exp1) … (varn expn)) exp ) exp1 to expn are evaluated in the surrounding context. var1,…,varn are visible only in exp. (let ( (x 2) (y 7) ) y) 7 cs7100(Prasad) L3Scheme
(let ( (x y) (y 7) ) y) *error* “y” undefined (define y 5) 7 (let ( (x y) (y 7) ) x) 5 (let ( (y 7) (x y) ) x) 5 (not 7) cs7100(Prasad) L3Scheme
let* abbreviates nested-lets. (define y 5) (let ( (y 7) (x y) ) x) 5 (let ( (y 7) ) (let ( (x y) ) x) ) 7 (let* ( (y 7) (x y) ) x) let* abbreviates nested-lets. Recursive and mutually recursive functions cannot be defined using let and let*. cs7100(Prasad) L3Scheme
letrec-construct ( letrec ( (var1 exp1) … (varn expn)) exp ) var1,…,varn are visible in exp1 to expn in addition to exp. (letrec ( (x (lambda() y)) (y (lambda() x)) ) x ;Value 1: #[compound-procedure 1 x] RACKET => #<procedure:x> (letrec ( (x (lambda() y) (y (lambda() x) ) ((((((x)))))) ) ;Value 2: #[compound-procedure 2 x] (letrec ((x (lambda()y)) (y (lambda () x))) (x)) ;Value 3: #[compound-procedure 3 y] (letrec ( (x (lambda() y)) (y (lambda() x)) ) x Similar to: (define x (lambda() y) ) (define y (lambda() x) ) ((x)) #<procedure:x> > (letrec ( (x (lambda() y)) (x) #<procedure:y> > cs7100(Prasad) L3Scheme
letrec-construct (letrec ( (f (lambda(n) (if (zero? n) 1 (f (- n 1)) )) ) ) (f 5) ) 1 (letrec ( ( f (lambda () g) ) ( g 2 ) ) ( f ) 2 (letrec ( (f (lambda(n) (if (zero? n) 1 (f (- 1 n)) )) ) ) (f 5) ) INFINITE LOOP cs7100(Prasad) L3Scheme
boolean connectives (or test1 test2 … testn) (and test1 test2 … testn) or and and are not Scheme procedures. They use short circuit evaluation rather than traditional call-by-value. cs7100(Prasad) L3Scheme
Branching constructs (cond (test1 exp1) (test2 exp2) … (testn expn) (else exp) ) (case key (keylist1 exp1) (keylist2 exp2) … (keylistn expn) (else exp) ) (case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite)) ===> composite (case (car '(c d)) ((a) 'a) ((b) 'b)) ===> unspecified ((a e i o u) 'vowel) ((w y) 'semivowel) (else 'consonant)) ===> consonant cs7100(Prasad) L3Scheme