440 likes | 584 Vues
This course provides a detailed introduction to Scheme, a functional programming language characterized by its elegant syntax and emphasis on function definition over imperative constructs. With a focus on recursion, dynamic typing, and basic constructs such as forms and evaluation, students will learn the nuances of evaluating Scheme expressions, defining variables, and utilizing special forms. Through practical examples, we will illustrate the power of Scheme in functional programming and its rising significance in educational settings like Caltech and MIT.
E N D
CS 480/680 – Comparative Languages Introduction to Scheme “And now for something completely different…” – Monty Python
Functional Languages • Scheme is a functional language. It belongs to a class of languages that differ from imperative languages in a number of ways: • Elegant, concise, syntax (and specification). • Definition of functions is paramount – Order is not that important! • No iteration! -- Use of recursion instead. • Data is generally weakly/dynamically typed. Intro to Scheme
Why Scheme? • Very simple syntax (the E-BNF specification is only 8 pages – see the last slides) • Lisp is the standard for functional languages, Scheme is a rising star • Many efforts to make it a teachable language • Cal-Tech, MIT, etc. • DR-Scheme Intro to Scheme
Forms and Evaluation • The basic scheme construct is called a form • (function argument1 argument2 argument3…) • (+ 2 5) » 7 • (+ 3 4 5) » 12 • (/ 22 7) » 22/7 • (number? 5) » #t • (boolean? 5) » #f • (boolean? #5) » #t • (eqv? 42 42) » #t • (eqv? 42 42.0) » #f • (= 42 42.0) » #t • (= 42 #x2A) » #t • (expt 4 2) » 16 • (expt 4 1/2) » 2 • (max 1 3 5 7) » 7 • (min 1 3 5 7) » 1 • (abs -2) » 2 • (abs -2 5) abs: expects 1 argument, given 2: -2 5 Intro to Scheme
Substitution Model The basic rule: To evaluate a Scheme expression: • Evaluate its operands • Evaluate the operator • Apply the operator to the evaluated operands Intro to Scheme
Warning!Boredom ahead! • We will walk through evaluations • in painful, excruciating detail • Not the most exciting part of course • but necessary to give a precise model Intro to Scheme
Example expression eval • Example: (+ 3 (* 4 5) ) Intro to Scheme
operator Example expression eval • Example: (+3 (* 4 5) ) Intro to Scheme
operator operand 1 Example expression eval • Example: (+3 (* 4 5) ) Intro to Scheme
operator operand 1 operand 2 Example expression eval • Example: (+3 (* 4 5)) Intro to Scheme
Example expression eval • Example: (+ 3 (* 4 5)) • evaluate 3 • evaluate (* 4 5) • evaluate 4 • evaluate 5 • evaluate * • apply * to 4, 5 20 • evaluate + • apply + to 3, 20 23 Intro to Scheme
Primitive expressions • Numbers evaluate to themselves • 105 105 • Primitive procedures • +, -, *, /, abs … • evaluate to the corresponding internal procedure • e.g. "+" evaluates to the procedure that adds numbers together • Can write this as: + + • or as: + [primitive procedure +] • write this out explicitly for now Intro to Scheme
Another example • (+ 3 (- 4 (* 5 (expt 2 2)))) • evaluate 3 3 • evaluate (- 4 (* 5 (expt 2 2))) • evaluate 4 4 • evaluate (* 5 (expt 2 2)) • evaluate 5 5 • evaluate (expt 2 2) • evaluate 2 2, evaluate 2 2, expt expt • apply expt to 2, 2 4 • evaluate * * • apply * to 5, 4 20 • apply - to 4, 20 -16 • apply + to 3, -16 -13 Intro to Scheme
Evaluation with variables • An assignment provides an association between a symbol (variable) and its value (definex 3) • Here x is the variable, 3 is the value • To evaluate a variable: • look up the value associated with the variable • and replace the variable with its value Intro to Scheme
Variable evaluation example • (definex 3) • Then evaluate x • look up value of x • x has value 3 (due to define) • result: 3 Intro to Scheme
Simple expression evaluation • Assignment and evaluation (define x 3) (define y 4) • evaluate (+ x y) • evaluate x 3 • evaluate y 4 • evaluate + [primitive procedure +] • apply + to 3, 4 7 Intro to Scheme
Special forms • N.B. There are a few special formswhich do not evaluate in the way we’ve described. • define is one of them (definex 3) • We do not evaluate x before applying define to x and 3 • Instead, we • evaluate the second operand (3 3) • make an association between it and the first operand (x) Intro to Scheme
Special forms • Another example: (definex (+ 2 3)) • Evaluate (+ 2 3) • evaluate 2 2 • evaluate 3 3 • evaluate + [primitive procedure +] • apply + to 2, 3 5 • Make association between x and 5 • details of how association is made aren't important Intro to Scheme
Basic Data Types • Numbers: 3, -3, 22/7, 3+2i, #xF3A, #o721, #b110110, 3.1416 (= 42 #x2A) » #t • Single characters: #\c, #\newline, #\tab, #\space • (char? #\c), (char=? #\c #\b), (char<=? #\c #\b) • Strings: “Hello World” • (string #\h #\i) • (string-ref “Hello” 1) » #\e • (string-append “E” “Pluribus” “Unum”) » “E Pluribus Unum” Intro to Scheme
More types • Procedures (lambda) • Booleans (#t and #f) Intro to Scheme
Symbols • Symbols have two parts, a name and a value • Similar to variables in other languages, but beware of the many differences! • We’ll see a lot more about the differences later. • (define xyz 9) • xyz » 9 • (symbol? xyz) » #f • (symbol? ’xyz) » #t • (set! xyz 8) • (set! qrs 7) set!: cannot set undefined identifier: qrs Intro to Scheme
Arbitrary Data Structures • What is the simplest data structure that you can use to create any other data structure, including dynamically sized structures? • What is the smallest component of this structure? Intro to Scheme
1 2 Dotted Pairs • Scheme uses pairs for many, many things • Programs (forms) • Arguments • Data structures • A pair is a two-cell node. Each cell contains a pointer to a value or another pair. • A node with two pointers is called a dotted pair • (cons 1 2) » (1 . 2) • ’(1 . 2) » (1 . 2) Intro to Scheme
car and cdr • You access the two parts of a dotted pair with the accessors car and cdr: • (define x (cons 1 2)) • (car x) » 1 • (cdr x) » 2 • (pair? a) returns true if a is a dotted pair • (pair? (cons 3 4)) » #t • (pair? 3) » #f Intro to Scheme
3 1 4 2 Dotted pairs can be nested • (define x (cons (cons 1 2) (cons 3 4)) • (define x ‘((1 . 2) . (3 . 4))) • (car x) » (1 . 2) • (cdr x) » (3 . 4) Intro to Scheme
Scheme shorthand • (cons 1 (cons 2 (cons 3 (cons 4 5)))) » (1 2 3 4 . 5) • (1 2 3 4 . 5) is an abbreviation for (1 . (2 . (3 . (4 . 5)))) 1 2 3 4 5 Intro to Scheme
Lists • ’(1 2 3 4) » (1 2 3 4) • (1 2 3 4) is an abbreviation for (1 . (2 . (3 . (4 . ())))) • Just like a standard linked list • An empty list, ’(), is essentially a null pointer • This is often how parameters are passed, etc. This special construct of nested dotted pairs is called a list 1 2 3 4 Intro to Scheme
List() (list 1 2 3 4 5) Is the same as… (cons 1 (cons 2 (cons 3 (cons 4 cons 5 nil)))) Both produce: (1 . (2 . (3 . (4 . (5 . ()))))) Or, as scheme would print it… (1 2 3 4 5) Intro to Scheme
car and cdr • The car of a list is a value • The cdr of a list is a list • Special names: cadr, cddr, cdar, etc. • (define x ’(1 2 3 4 5) • (car x) » 1 • (cdr x) » (2 3 4 5) • (cadr x) » 2 • (cddr x) » (3 4 5) Intro to Scheme
Quote and Lists • ‘(item1, item2, item3, …) is syntactic sugar for (list ‘item1 ‘item2 ‘item3 …) • ‘(1 2 3 4 5)»(1 2 3 4 5) • ‘(a b c d e)»(a b c d e) • ‘(1 2 3 4 5) procedure application: expected procedure, given: 1; arguments were: 2 3 4 5 Intro to Scheme
Equivalence • (eq? item item) checks for object equivalence. Are the two variables bound/pointing to the same object? (define l '(a b c)) (eq? l '(a b c)) » #f (define a l) (eq? a l) » #t (define a 3) (eq? a 3) » #t Intro to Scheme
Equivalence (2) • Equal? Recursively performes eq? on each entry in a list, etc. • Most types have their own equality operations • (char=? #\c #\b) • (= 3 3.0), etc. (define l '(a b c)) (equal? l '(a b c)) » #t Intro to Scheme
Vectors • Scheme’s answer to arrays are called vectors • Not used as much as lists • (define x (vector 1 2 3 4 5))x » #(1 2 3 4 5) • (vector-ref x 3) » 4 • (vector-set! x 2 1) x » #(1 2 1 4 5) Intro to Scheme
Conversion between data types • (char->integer #\d) » 100 • (integer->char 50) » #\2 • (string->list “hi!”) » (#\h #\i #\!) • (number->string 23) » “23” • (string->number “20”) » 20 • (string->number “bob”) » #f • (string->number “23” 16) » 35 • (symbol->string xyz) » “xyz” • (string->symbol “xyz”) » xyz All these data types are special cases of Scheme S-expressions Intro to Scheme
Problems • Draw the linked list structure that would result from each of the following expressions: (cons (cons (cons a b) c (cons d e)) f) (cons (cons (cons (cons a b) c) d) ()) ’(a b c (d e (f . g))) ’(1 2 3 (4 . 5) . 6) Intro to Scheme
7.1.1 Lexical structure • This section describes how individual tokens (identifiers, numbers, etc.) are formed from sequences of characters. The following sections describe how expressions and programs are formed from sequences of tokens. • <Intertoken space> may occur on either side of any token, but not within a token. • Tokens which require implicit termination (identifiers, numbers, characters, and dot) may be terminated by any <delimiter>, but not necessarily by anything else. • The following five characters are reserved for future extensions to the language: [ ] { } | • <token> --> <identifier> | <boolean> | <number> • | <character> | <string> • | ( | ) | #( | ' | ` | , | ,@ | . • <delimiter> --> <whitespace> | ( | ) | " | ; • <whitespace> --> <space or newline> • <comment> --> ; <all subsequent characters up to a • line break> • <atmosphere> --> <whitespace> | <comment> • <intertoken space> --> <atmosphere>* • <identifier> --> <initial> <subsequent>* • | <peculiar identifier> • <initial> --> <letter> | <special initial> • <letter> --> a | b | c | ... | z • <special initial> --> ! | $ | % | & | * | / | : | < | = • | > | ? | ^ | _ | ~ • <subsequent> --> <initial> | <digit> • | <special subsequent> • <digit> --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 • <special subsequent> --> + | - | . | @ • <peculiar identifier> --> + | - | ... • <syntactic keyword> --> <expression keyword> • | else | => | define • | unquote | unquote-splicing
<expression keyword> --> quote | lambda | if | set! | begin | cond | and | or | case | let | let* | letrec | do | delay | quasiquote `<variable> => <'any <identifier> that isn't also a <syntactic keyword>> <boolean> --> #t | #f <character> --> #\ <any character> | #\ <character name> <character name> --> space | newline <string> --> " <string element>* " <string element> --> <any character other than " or \> | \" | \\ <number> --> <num 2>| <num 8> | <num 10>| <num 16> The following rules for <num R>, <complex R>, <real R>, <ureal R>, <uinteger R>, and <prefix R> should be replicated for R = 2, 8, 10, and 16. There are no rules for <decimal 2>, <decimal 8>, and <decimal 16>, which means that numbers containing decimal points or exponents must be in decimal radix. <num R> --> <prefix R> <complex R> <complex R> --> <real R> | <real R> @ <real R> | <real R> + <ureal R> i | <real R> - <ureal R> i | <real R> + i | <real R> - i | + <ureal R> i | - <ureal R> i | + i | - i <real R> --> <sign> <ureal R> <ureal R> --> <uinteger R> | <uinteger R> / <uinteger R> | <decimal R>
<decimal 10> --> <uinteger 10> <suffix> • | . <digit 10>+ #* <suffix> • | <digit 10>+ . <digit 10>* #* <suffix> • | <digit 10>+ #+ . #* <suffix> • <uinteger R> --> <digit R>+ #* • <prefix R> --> <radix R> <exactness> • | <exactness> <radix R> • <suffix> --> <empty> • | <exponent marker> <sign> <digit 10>+ • <exponent marker> --> e | s | f | d | l • <sign> --> <empty> | + | - • <exactness> --> <empty> | #i | #e • <radix 2> --> #b • <radix 8> --> #o • <radix 10> --> <empty> | #d • <radix 16> --> #x • <digit 2> --> 0 | 1 • <digit 8> --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 • <digit 10> --> <digit> • <digit 16> --> <digit 10> | a | b | c | d | e | f • 7.1.2 External representations • <Datum> is what the read procedure (section see section 6.6.2 Input) successfully parses. Note that any string that parses as an <expression> will also parse as a <datum>. • <datum> --> <simple datum> | <compound datum> • <simple datum> --> <boolean> | <number> • | <character> | <string> | <symbol> • <symbol> --> <identifier> • <compound datum> --> <list> | <vector>
<list> --> (<datum>*) | (<datum>+ . <datum>) • | <abbreviation> • <abbreviation> --> <abbrev prefix> <datum> • <abbrev prefix> --> ' | ` | , | ,@ • <vector> --> #(<datum>*) • 7.1.3 Expressions • <expression> --> <variable> • | <literal> • | <procedure call> • | <lambda expression> • | <conditional> • | <assignment> • | <derived expression> • | <macro use> • | <macro block> • <literal> --> <quotation> | <self-evaluating> • <self-evaluating> --> <boolean> | <number> • | <character> | <string> • <quotation> --> '<datum> | (quote <datum>) • <procedure call> --> (<operator> <operand>*) • <operator> --> <expression> • <operand> --> <expression> • <lambda expression> --> (lambda <formals> <body>) • <formals> --> (<variable>*) | <variable> • | (<variable>+ . <variable>) • <body> --> <definition>* <sequence> • <sequence> --> <command>* <expression> • <command> --> <expression>
<conditional> --> (if <test> <consequent> <alternate>) <test> --> <expression> <consequent> --> <expression> <alternate> --> <expression> | <empty> <assignment> --> (set! <variable> <expression>) <derived expression> --> (cond <cond clause>+) | (cond <cond clause>* (else <sequence>)) | (case <expression> <case clause>+) | (case <expression> <case clause>* (else <sequence>)) | (and <test>*) | (or <test>*) | (let (<binding spec>*) <body>) | (let <variable> (<binding spec>*) <body>) | (let* (<binding spec>*) <body>) | (letrec (<binding spec>*) <body>) | (begin <sequence>) | (do (<iteration spec>*) (<test> <do result>) <command>*) | (delay <expression>) | <quasiquotation> <cond clause> --> (<test> <sequence>) | (<test>) | (<test> => <recipient>) <recipient> --> <expression> <case clause> --> ((<datum>*) <sequence>) <binding spec> --> (<variable> <expression>) <iteration spec> --> (<variable> <init> <step>)
| (<variable> <init>) • <init> --> <expression> • <step> --> <expression> • <do result> --> <sequence> | <empty> • <macro use> --> (<keyword> <datum>*) • <keyword> --> <identifier> • <macro block> --> • (let-syntax (<syntax spec>*) <body>) • | (letrec-syntax (<syntax spec>*) <body>) • <syntax spec> --> (<keyword> <transformer spec>) • 7.1.4 Quasiquotations • The following grammar for quasiquote expressions is not context-free. It is presented as a recipe for generating an infinite number of production rules. Imagine a copy of the following rules for D = 1, 2,3, .... D keeps track of the nesting depth. • <quasiquotation> --> <quasiquotation 1> • <qq template 0> --> <expression> • <quasiquotation D> --> `<qq template D> • | (quasiquote <qq template D>) • <qq template D> --> <simple datum> • | <list qq template D> • | <vector qq template D> • | <unquotation D> • <list qq template D> --> (<qq template or splice D>*) • | (<qq template or splice D>+ . <qq template D>) • | '<qq template D> • | <quasiquotation D+1>
<vector qq template D> --> #(<qq template or splice D>*) • <unquotation D> --> ,<qq template D-1> • | (unquote <qq template D-1>) • <qq template or splice D> --> <qq template D> • | <splicing unquotation D> • <splicing unquotation D> --> ,@<qq template D-1> • | (unquote-splicing <qq template D-1>) • In <quasiquotation>s, a <list qq template D> can sometimes be confused with either an <unquotation D> or a <splicing unquotation D>. The interpretation as an <unquotation> or <splicing unquotation D> takes precedence. • 7.1.5 Transformers • <transformer spec> --> • (syntax-rules (<identifier>*) <syntax rule>*) • <syntax rule> --> (<pattern> <template>) • <pattern> --> <pattern identifier> • | (<pattern>*) • | (<pattern>+ . <pattern>) • | (<pattern>* <pattern> <ellipsis>) • | #(<pattern>*) • | #(<pattern>* <pattern> <ellipsis>) • | <pattern datum> • <pattern datum> --> <string> • | <character> • | <boolean> • | <number> • <template> --> <pattern identifier> • | (<template element>*) • | (<template element>+ . <template>) • | #(<template element>*) • | <template datum> • <template element> --> <template> • | <template> <ellipsis>
<template datum> --> <pattern datum> • <pattern identifier> --> <any identifier except `...'> • <ellipsis> --> <the identifier `...'> • 7.1.6 Programs and definitions • <program> --> <command or definition>* • <command or definition> --> <command> • | <definition> • | <syntax definition> • | (begin <command or definition>+) • <definition> --> (define <variable> <expression>) • | (define (<variable> <def formals>) <body>) • | (begin <definition>*) • <def formals> --> <variable>* • | <variable>* . <variable> • <syntax definition> --> • (define-syntax <keyword> <transformer spec>)