410 likes | 505 Vues
A Scheme Refresher. (Functional Subset) Prabhaker Mateti. Overview of Scheme. Guy Steele and Gerald Sussman , MIT, 1975 Interpreted or compiled to machine code REPL (Read, Eval , Print, Loop) Like Python, MatLab Lisp syntax + lexical scope Lists are a fundamental built-in data type
E N D
A Scheme Refresher (Functional Subset) PrabhakerMateti
SchemeRefresher Overview of Scheme • Guy Steele and Gerald Sussman, MIT, 1975 • Interpreted or compiled to machine code • REPL (Read, Eval, Print, Loop) • Like Python, MatLab • Lisp syntax + lexical scope • Lists are a fundamental built-in data type • Everything in prefix form: • (+ a b) instead of the infix a + b • Procedures represented by computable data structures
SchemeRefresher Standards Docs for Scheme • Official Standard: The IEEE standard, 1178-1990 (R1995) standards.ieee.org/ • De Facto Std: R6RS (2007) Revised^6 Report on the Algorithmic Language Scheme www.r6rs.org/ • Older R5RS (1998) www.schemers.org/ Documents/Standards/R5RS/
SchemeRefresher “Implementations” of Scheme • Many (~100 ?) that meet R5RS and R6RS. • On Linux, Windows, … • CS784 choice: http://racket-lang.org/ • Previously (< June 2010) known as PLT-Scheme • DrRacket, … • “Determine language from source” • EOPL3 • Many extensions
SchemeRefresher Scheme Reading • Teach Yourself Scheme in Fixnum Days, DoraiSitaram, free download, www.ccs. neu.edu/home/dorai/ (For programmers.) • How to Design Programs, Felleisen, Bruce Findler, Flatt and Krishnamurthi, MIT Press, 2001. on-line www.htdp.org/ (For beginners.) • Scheme Wiki: community.schemewiki.org/
SchemeRefresher Examples, Discussion, … • http://community.schemewiki.org/ • http://practical-scheme.net/ • http://www.schemers.org/ • http://lambda-the-ultimate.org/
SchemeRefresher Examples-1 • (define x 10) • (define y 20) • (cons x y) • (cdr (cons x y)) • (symbol? '123) • (string->symbol "one, two")
SchemeRefresher Examples-2 • (define list-length • (lambda (lst) • (if (null? lst) • 0 • (+ 1 (list-length (cdrlst)))))) • (define remove-first • (lambda (s los) • (if (null? los) • '() • (if (eqv? (car los) s) • (cdr los) • (cons (car los) (remove-first s (cdr los)))))))
SchemeRefresher Example-3 EOPL3 p19 • (define occurs-free? • (lambda (var exp) • (cond • ((symbol? exp) (eqv? var exp)) • ((eqv? (car exp) 'lambda) • (and • (not (eqv? var (car (cadr exp)))) • (occurs-free? var (caddr exp)))) • (else • (or • (occurs-free? var (car exp)) • (occurs-free? var (cadr exp)))))))
SchemeRefresher Example-4 EOPL3 p21 • (define subst-in-s-exp • (lambda (new old sexp) • (if (symbol? sexp) • (if (eqv? sexp old) new sexp) • (subst new old sexp)))) • (subst 'a 'b '((b c) (b () d))) '((a c) (a () d))
SchemeRefresher Example-5 EOPL3 p23 • (define number-elements-from • (lambda (lst n) • (if (null? lst) '() • (cons • (list n (car lst)) • (number-elements-from (cdrlst) (+ n 1)))))) • (define number-elements • (lambda (lst) • (number-elements-from lst 0))) • (number-elements '(a b c d e)) '((0 a) (1 b) (2 c) (3 d) (4 e))
SchemeRefresher Built-In Data Types • Booleans: #t #f • Numbers • Characters • Strings (Unicode) • Bytes and Byte Strings • Symbols • Keywords • Pairs and Lists • Vectors • Hash Tables • Boxes • Void and Undefined
Four Types Of Expressions • Constants: numbers, booleans. • Variables: names for values. Created using the special form define • Special forms have special rules for evaluation. • Cannot be redefined • 15 “magic words” and, begin, case, cond, define, do, if, lambda, let, let*, letrec, or,quasiquote, quote, set! • a special form is not a first-class object like a procedure • Combination: (operator operands) • "function calls" or • "procedure applications."
Mantras of Scheme • Every expression has a value • except for • errors, • infinite loops, and • define special form • Computing the value of a combination • (operator operands …) • Compute all sub-expressions (in any order) • Apply the value of the first to the values of the rest • Applicative Order • The value of a lambda expression is a procedure
SchemeRefresher Expressions • Literals • 2, 22/7, 3.1, "abc", #t • '(define x 12) • Variables • (define x 12) • x • Function Calls (aka Procedure Applications) • ( ‹id› ‹expr›* )
SchemeRefresher Symbols • A symbol is an atomic value. • An expression that starts with ' and continues with an identifier. • Distinct from identifiers that name variables in the program text. • Distinct from strings (sequence of characters). • Examples • (symbol? 'blah) #t • (string->symbol "one, two“) |one, two|
SchemeRefresher Pairs • cons procedure: • (cons x y) constructs a pair (10 . 20) • (cons '() 'blah) (() . blah) • (cons "blah" '()) ("blah") • (cons 'blah '()) (blah) • car procedure: first value • cdr procedure: second value • (cdr (cons x y)) 20 • (pair? '(1 2)) #t
SchemeRefresher Lists • A list is recursively defined: • the constant null, or • a pair whose second value is a list. • Ordered sequence of elements of arbitrary types (Heterogeneous) • (list? (cons alpha (cons 2 '()))) #t • (list? (cons alpha 2)) #f
SchemeRefresher Procedure Call/Application • ( ‹id› ‹expr›* ) • (proc exp1 exp2 exp3 ...) is in other languages proc(exp1 exp2 exp3 ...) • (equal? 6 "half dozen") • ((f #t 3) (string? s) 6) • Order of evaluation of the sub-expressions is deliberately left unspecified by Scheme. • cf. C is silent about it. • cf. Java specifies a left to right processing.
SchemeRefresher procedure: (eq? v1 v2) • Return #t if v1 and v2 refer to the same object, #f otherwise • (eq? 'yes 'yes) #t • (eq? "yes" "yes" ) #f • (eq? (cons 1 2) (cons 1 2)) #f
SchemeRefresher procedure: (eqv? v1 v2) • Two values are eqv? if and only if they are eq?, • except for number and character data types • (eqv? (expt 2 100) (expt 2 100)) #t • (eq? (expt 2 100) (expt 2 100)) #f
SchemeRefresher procedure: (equal? v1 v2) • Two values are equal? if and only if they are eqv?, • except for strings, byte strings, numbers, pairs, mutable pairs, vectors, hash tables, and inspectable structures. • A rule of thumb is that objects are generally equal? if they print the same. • For precise details, see the docs of Scheme implementation you are using.
SchemeRefresher eq? eqv? equal? • (equal? (expt 2 100) (expt 2 100)) #t • (eqv? (expt 2 100) (expt 2 100)) #t • (eq? (expt 2 100) (expt 2 100)) #f • (equal? (make-string 3 #\z) (make-string 3 #\z)) #t • (eqv? (make-string 3 #\z) (make-string 3 #\z)) #f • (eq? (make-string 3 #\z) (make-string 3 #\z)) #f
SchemeRefresher procedure: (vector v ...) • Returns a new mutable “array” with the slots initialized to contain the given v … in order. Index starts at 0. • (vector 'a 20 "yes") #(a 20 "yes") • (define v (vector 'a 20 "yes")) • (vector-ref v 2) "yes“ • (vector-length v) 3 • (vector->list v) (a 20 "yes") • (list->vector '(a 20 "yes")) #(a 20 "yes") • (build-vector 5 add1) '#(1 2 3 4 5)
SchemeRefresher Special Forms • A special form is an expression that follows special evaluation rules. • Lambda Expressions • Definitions • Assignments • Conditionals • Sequencing • Iteration
SchemeRefresher (defineidexpr) • binds id to the result of expr • (define x 10) • (define v (vector 'a 20 "yes"))
SchemeRefresher (define (headargs) body ...+) • binds id, in the head, to a procedure. • (define (f x) (+ x 1)) • (define ((f x)) (+ x 20)) • ((f 10)) 30 • (f 10) #<procedure>
SchemeRefresher (define fnid (lambda (id …) …) • (define (factx n) • (if (= n 0) 1 • (* n (facty (- n 1))))) • (factx 4) 24 • (define facty • (lambda (n) • (if (= n 0) 1 • (* n (facty (- n 1)))))) • (facty 4) 24 • (equal? factx facty) #f • (eqv? factx facty) #f • (eq? factx facty) #f
SchemeRefresher Procedures are first-class data • The definition of a procedure is stored as a data structure. • Can pass them as arguments to other procedures. • A procedure can create and return another procedure.
SchemeRefresher define-syntax • (define-syntax idexpr) • (define-syntax foo • (syntax-rules () • ((_ a ...) • (printf "~a\n" (list a ...))))) • (foo 1 2 3 4) (1 2 3 4) • (define-syntax (headargs) body ...+) • (define-syntax (bar syntax-object) • (syntax-case syntax-object () • ((_ a ...) • #'(printf "~a\n" (list a ...))))) • (bar 1 2 3 4) (1 2 3 4)
SchemeRefresher (define-syntax equal?? …) • (define-syntax equal?? • (syntax-rules () • ((_ test-exp correct-ans) • (let ((observed-ans test-exp)) • (if (not (equal? observed-ans correct-ans)) • (printf "~s returned ~s, should have returned ~s~%" • 'test-exp • observed-ans • correct-ans) • (printf "pmateti ~s OK~%" • 'test-exp))))))
SchemeRefresher (applyprocv ... ) → any • Applies proc using the content of v... as the (by-position) arguments. • (apply + 1 2 '(3)) 6 • (define compose (lambda (f g) (lambda args (f (apply g args)))))((compose sqrt *) 12 75) 30
SchemeRefresher (lambda formals body) • A lambda expression evaluates to an anonymous procedure. • (lambda (x) (+ 12 x)) #<procedure> • ((lambda (x) (+ 12 x)) 20) 32 • ((lambda (x y) (list y x)) 1 2) '(2 1) • ((lambda (x [y 5]) (list y x)) 1 2) '(2 1)
SchemeRefresher Local Binding: let • (let ([idval-expr] ...) body ...+) • Evaluates the val-exprs left-to-right, creates a new location for each id, and places the values into the locations. It then evaluates the bodys, in which the ids are bound. • (let ([x 5]) • (let ([x 2] • [y x]) • (list y x))) '(5 2)
SchemeRefresher Local Binding: let • (letproc-id ([idinit-expr] ...) body ...+) • Defines a local procedure. Evaluates the init-exprs; these become arguments to the proc. The ids must be distinct. • (let fac ([n 10]) • (if (zero? n) • 1 • (* n (fac (sub1 n))))) 3628800
SchemeRefresher Local Binding: let* • (let* ([idval-expr] ...) body ...+) • Similar to let, but evaluates the val-exprs one by one, creating a location for each id as soon as the value is available. The ids are bound in the remainingval-exprs as well as the bodys, and the ids need not be distinct; later bindings shadow earlier bindings. • (let* ([x 1] • [y (+ x 1)]) • (list y x)) (2 1)
SchemeRefresher Local Binding: letrec • (letrec ([idval-expr] ...) body ...+) • Similar to let, but the locations for all ids are created first and filled with #<undefined>, and all ids are bound in all val-exprs as well as the bodys. The ids must be distinct. • (letrec ((a b) (b 34) (c (+ b 5))) • (list a b c)) (#<undefined> 34 39) • (letrec ([is-even? (lambda (n) • (or (zero? n) • (is-odd? (sub1 n))))] • [is-odd? (lambda (n) • (and (not (zero? n)) • (is-even? (sub1 n))))]) • (is-odd? 11)) #t
SchemeRefresher Comparison: let, let*, letrec • (let/let*/letrec ((v1 e1 ) (v2 e2 ) … (vn en )) body ) • let • no vi is created until all ei are evaluated. • none of ei can refer to any vi • let* • e1 is evaluated; v1 created, bound to e1; • e2 is evaluated; v2 created, bound to e2; …; • ej can refer to earlier vi, i < j. • letrec • vi are created with #undefined as their value. • with the above in effect, e1, …, en are evaluated l-to-r • each vi is now bound to ei
SchemeRefresher (iftestthen-expelse-exp) • If test produces any value other than #f, then then-exp is the result. Otherwise, else-exp is the result. • (if (> 3 2) (- 3 2) (+ 3 2)) 1 • (if 'we-have-no-bananas "yes" "no") "yes"
SchemeRefresher (cond clause1 clause2 ...) • clause ::= ( test expression ) • (cond • [(positive? -5) (error "doesn't get here")] • [(zero? -5) (error "doesn't get here, either")] • [(positive? 5) 'here]) here • (cond • [(member 2 '(1 2 3)) • => (lambda (x) (map - x))]) (-2 -3) • (cond [(member 2 '(1 2 3))]) (2 3)
SchemeRefresher (case key clause1 clause2 ...) • clause ::= ( keyList expression ) • (case (- 7 5) • [(1 2 3) 'small] • [(10 11 12) 'big]) 'small • (define (classify c) • (case (char-general-category c) • [(lllultln lo) "letter"] • [(ndnl no) "number"] • [else "other"])) • (classify #\A) "letter " • (classify #\1) "number" • (classify #\!) "other"