230 likes | 355 Vues
This chapter delves into the essential concepts of inductive data types in Scheme, focusing on the binary tree data structure. We explore the definition of a binary tree, its constructors, and predicates, along with practical examples for manipulating binary tree structures. Additionally, we cover the syntax for creating variant records, enabling rich representations of various data types. This is essential for effective programming in Scheme and developing a deep understanding of data abstraction techniques.
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)) • ) • )