Data Abstraction



Multi-way branches:

Special form CASE with the following syntax: 

(case key
  (key-list1 consuequent1)
  ...
  (key-listn consuequentn)
  (else alternative))

Each key-listi is a list of symbols, numbers,
booleans, or characters.

else clause is optional

Semantics:

- key is evaluated
- its value is compared with the key-list 
elements 
- the consequent corresponding to the first
matching key-list element is evaluated and its
value returned
- if no match, alternative is evaluated and its
value returned.
   If no else clause and no match case behavior is 
unspecified......



A case expression can always be transformed into
an equivalent expression using let and cond

(let [(*key* key)]
  (cond
    [(memv *key* 'key-list1) consequent1]
    ...
    [(memv *key* 'key-listn) consequentn]
    [else alternative]))

where the variable *key* does not occur-free
within the consequents or alternative.

memv is like member and uses the appropriate eq?,
=, char=? 

let is used so key is evaluated only once.



Records, unions, variant records and 
	DATA ABSTRACTION

We would like to have structures or records in our 
Programming Language.

Unlike arrays and vectors where members are
accessed by position/index, we want to access
elements by NAME.

record facility in scheme:
	not a standard feature


(define-record name (field1 ... fieldn))

This automatically/automagically defines:

1. a procedure for creating records of type name
constructor

2. A predicate for identifying records of this
type

3. An accessing procedure for each field
access methods


You need record.ss, 

Follow "Useful scheme code" link on main web page
under Resources 





Consider
binary trees:

TREE ::== NUMBER | (SYMBOL TREE TREE)

Interior nodes are 
	(SYMBOL TREE TREE)

let us make a record type called interior

(define-record interior 
  (symbol left-tree right-tree))

(define tree-1
  (make-interior
    'foo
    (make-interior 'bar 1 2)
    3))

Petite Chez Scheme Version 6.0a
Copyright (c) 1998 Cadence Research Systems

> > > #t
> (interior? tree-1)
#t
> (interior->symbol tree-1)
foo
> (interior->right-tree 
    (interior->left-tree  tree-1))
2
> 



constructor: make-name

predicate  : name?

access     : name-fieldi

(define leaf-sum
  (lambda (tree)
    (cond
      [(number? tree) tree]
      [(interior? tree)
       (+
	 (leaf-sum (interior->left-tree tree))
	 (leaf-sum (interior->right-tree tree)))]
      [else (error 'leaf-sum "Invalid tree")])))

> (leaf-sum '(a 1 2))



> (leaf-sum (make-interior 'a 1 2))
3


In general a distinct record type can be used to
represent each alternative of a BNF specification

TREE ::== NUMBER | (SYMBOL TREE TREE)

we got a record for interior nodes

one for leaf

(define-record leaf (number))

Can you define leaf-sum for trees with
leaf records?



Variant Records and variant-case

A type that combines two or more other types as
alternatives is called a UNION type

tree is a union of 
	records of type leaf and interior 

A union type all of whose alternatives are records 
is called a VARIANT RECORD

We use a lot of variant records in this course so
we combine this type with branching on the type of 
record. 

Once you know the type, it is also useful to bind
some or all of its field values to variables named
after the fields

THEREFORE create the special form

	variant-case




Syntax:

(variant-case record-expression
  (name1 flist1 conseq1)
  ...
  (namen flistn conseqn)
  (else alternative))


Semantics:

flisti is a list of fields for records of type
namei 

Each record type should be distinct, as should
field names within a list

1. Record-expression is evaluated with a resulting 
value V

2. if V is not a record of one of namei,
alternative is evaluated

3. Else if V is one of namei
     each of the fieldnames in flisti
     is bound to the value of the field of V with
     the same fieldname

4. Consequent is evaluated withing the region of
these bindings and its value returned.



(define-record leaf (number))

(define-record interior 
  (symbol left-tree right-tree))

(define leaf-sum2
  (lambda (tree)
    (variant-case tree
      [leaf (number) number]
      [interior (left-tree right-tree)
	(+ (leaf-sum2 left-tree)
	  (leaf-sum2 right-tree))]
      [else (error 'leaf-sum2 "invalid tree")])))


> (leaf-sum2 (make-interior 'a  1 2))
error



> (leaf-sum2 
    (make-interior 'a 
		   (make-leaf 1) 
                   (make-leaf 2)))




Otherwise:


(define leaf-sum3
  (lambda (tree)
    (let ((*record* tree))
      (cond
	[(leaf? *record*)
	 (let ((number (leaf->number *record*)))
	   number)]
	[(interior? *record*)
	 (let 
           ((left-tree 
              (interior->left-tree *record*))
	    (right-tree 
              (interior->right-tree *record*)))
	   (+ (leaf-sum3 left-tree)
	      (leaf-sum3 right-tree)))]
	[else (error 'leaf-sum3 "Invalid tree")]))))




Remember we want to build an interpreter!

Abstract Syntax and representation with
variant-case

We need to convert BNF (concrete syntax) to
  Rules associated with each syntactic component 
  Easy access to each subcomponent


exp ::==  NUMBER
        | VARREF
        | (lambda (VAR) EXP)
        | (EXP EXP)

exp ::== NUMBER

RuleName:    lit
NonTerminal: datum

variant-case representation:

	lit (datum) ...

The rest

	lit    (datum)
        varref (var)
        lambda (formal body) 
        app (rator rands)




consider 

(lambda (x) (f (f x)))



















Since scheme already reads characters from
input and gives you lists structures parsing is
real simple.....

We want to parse from list-structure into
variant-case usable representation

(define-record lit (datum))
(define-record varref (var))
(define-record lambda (formal body))
(define-record app (rator rand))

(define parse
  (lambda (datum)
    (cond
      [(number? datum) (make-lit datum)]
      [(symbol? datum) (make-varref datum)]
      [(pair? datum)
       (if (eq? (car datum) 'lambda)
	   (make-lambda
	     (caadr datum)
	     (parse (caddr datum)))
	   (make-app
	     (parse (car datum))
	     (parse (cadr datum))))]
      [else (error 'parse "Invalid concrete syntax")])))

concrete -> abstract

abstract -> concrete ??


    

Sushil Louis
Last modified: Mon Sep 27 14:21:31 PDT 1999