230 likes | 353 Views
Data Abstraction. Programming Language Essentials 2nd edition Chapter 2.2 An Abstraction for Inductive Data Types. define-datatype bintree. bintree: 'Number' | '(' 'Symbol' bintree bintree ')' (define-datatype bintree bintree? ( leaf-node (datum number?)) ( interior-node
E N D
Data Abstraction • Programming Language Essentials • 2nd edition • Chapter 2.2 AnAbstraction for Inductive Data Types
define-datatype bintree • bintree: 'Number' • | '(' 'Symbol' bintree bintree ')' • (define-datatype bintree bintree? • (leaf-node • (datum number?)) • (interior-node • (key symbol?) • (left bintree?) • (right bintree?))) • predicate • constructors
Scheme 48 Image • http://www.cs.indiana.edu/eopl/code.zip • $ scheme48 • > ,open srfi-23 • > ,load r5rs.scm • > ,load sllgen.scm • sllgen.scm 2000-09-25 11:48 • > ,load define-datatype.scm • define-datatype.scm version J3 2002-01-02 • > ,dump eopl.image EOPL • Writing eopl.image • $ scheme48 -i eopl.image • >
Terminology • aggregate: contains values of other types, e.g., array or record with named fields. • union: values are of other types. • discriminated union: value contains explanatory tag and value of union's types. • variant record: discriminated union of record types. • Scheme values are discriminated union of primitive types. • Inductively defined data types can be represented as variant records.
define-datatype • Scheme extension • (define-datatypetype-nametype-predicate-name • (variant-name • (field-name predicate) … • ) … • ) • creates variant record type with one or more variants with zero or more fields • type and variant names must be globally unique • must be used at top level
define-datatype (2) • creates type-predicate-name predicate with one argument • creates variant-name constructor with one argument per field • (define-datatype bintree bintree? • (leaf-node • (datum number?)) • (interior-node • (key symbol?) • (left bintree?) • (right bintree?)))
define-datatype (3) • (leaf-node 29) • (bintree? (leaf-node 29)) • (interior-node • 'foo (leaf-node 1) (leaf-node 2) • ) • (bintree? • (interior-node • 'foo (leaf-node 1) (leaf-node 2) • ) )
s-list • s-list: '(' symbol-expression* ')' • symbol-expression: 'Symbol' | s-list • (define-datatype s-list s-list? • (empty-s-list) • (non-empty-s-list • (first symbol-exp?) • (rest s-list?))) • (define-datatype symbol-exp symbol-exp? • (symbol-symbol-exp • (data symbol?)) • (s-list-symbol-exp • (data s-list?)))
s-list based on Scheme lists • (define-datatype s-list s-list? • (an-s-list • (data (list-of symbol-exp?)))) • (define list-of ; returns predicate for list • (lambda (pred) • (lambda (val) • (or (null? val) • (and (pair? val) • (pred (car val)) • ((list-of pred) (cdr val)) • ) ) ) ) )
Examples • (s-list? (empty-s-list)) • (s-list? • (non-empty-s-list (symbol-symbol-exp 'a) • (empty-s-list) • ) ) • (s-list? (an-s-list '())) • (s-list? • (an-s-list (list (symbol-symbol-exp 'a))) • ) • (s-list? • (an-s-list (cons (symbol-symbol-exp 'a) • '() • ) ) )
Sum of leaves of bintree • (define leaf-sum • (lambda (tree) • (cases bintree tree • (leaf-node (datum) datum) • (interior-node (key left right) • (+ (leaf-sum left) (leaf-sum right)) • ) ) ) ) • (leaf-sum • (interior-node • 'foo (leaf-node 1) (leaf-node 2) • ) )
cases • (casestype-nameexpression • (variant-name (field-name …) body) • … • (elsebody) • ) • value of expression must be of type-name • variant selects appropriate variant-name • each field value is bound to field-name and body is executed • without else, all variants must be specified
Lambda Calculus Representation • expr: 'Symbol' • | '(' 'lambda' '(' 'Symbol' ')' expr ')' • | '(' expr expr ')' • (define-datatype expression expression? • (var-exp • (id symbol?)) • (lambda-exp • (id symbol?) • (body expression?)) • (app-exp • (rator expression?) • (rand expression?)))
Examples • (expression? • (var-exp 'x) • ) • (expression? • (lambda-exp 'x (var-exp 'x)) • ) • (expression? • (app-exp (var-exp 'f) (var-exp 'x)) • ) • (expression? • (lambda-exp 'x • (app-exp (var-exp 'f) (var-exp 'x)) • ) )
Syntax and Representation • BNF specifies concrete syntax, external representation • define-datatype defines building blocks for abstract syntax, internal representation • expr: 'Symbol' • var-exp (id) • | '(' 'lambda' '(' 'Symbol' ')' expr ')' • lambda-exp (id body) • | '(' expr expr ')' • app-exp (rator rand)
Abstract Syntax Tree • lambda-exp • id body • x app-exp • rator rand • var-exp app-exp • id rator rand • f var-exp var-exp • id id • f x • (lambda (x) (f (f x)))
Programming without an AST • (define occurs-free? • (lambda (var exp) • (cond • ((symbol? exp) (eqv? var exp)) • ((eqv? (car exp) 'lambda) • (and (not (eqv? (caadr exp) var)) • (occurs-free? var (caddr exp)))) • (else (or (occurs-free? var (car exp)) • (occurs-free? var (cadr exp)) • ) ) ) ) ) • plagued by c*r references
Programming with an AST • (define occurs-free? • (lambda (var exp) • (cases expression exp • (var-exp (id) (eqv? id var)) • (lambda-exp (id body) • (and (not (eqv? id var)) • (occurs-free? var body))) • (app-exp (rator rand) • (or (occurs-free? var rator) • (occurs-free? var rand) • ) ) ) ) )
Example • (occurs-free? • 'f • (lambda-exp 'x • (app-exp (var-exp 'f) (var-exp 'x)) • ) )
unparse-expression • (define unparse-expression • (lambda (exp) • (cases expression exp • (var-exp (id) id) • (lambda-exp (id body) • (list 'lambda (list id) • (unparse-expression body) • ) ) • (app-exp (rator rand) • (list (unparse-expression rator) • (unparse-expression rand) • ) ) ) ) )
Example • (unparse-expression • (lambda-exp 'x • (app-exp (var-exp 'f) (var-exp 'x)) • ) )
parse-expression • (define parse-expression • (lambda (datum) • (cond • ((symbol? datum) (var-exp datum)) • ((pair? datum) • (if (eqv? (car datum) 'lambda) • (lambda-exp (caadr datum) • (parse-expression (caddr datum))) • (app-exp • (parse-expression (car datum)) • (parse-expression (cadr datum)) • ) ) ) • (else (error 'parse-expression datum)) • ) ) )
Example • (unparse-expression • (parse-expression • '(lambda (x) (f x)) • ) • )