RU beehive logo ITEC dept promo banner
ITEC 380
2011fall
ibarland

homelecturesexamshwsbreeze (snow day)

lect09b
data def'n for a grammar
internal representation of parse-tree

Mutable vs. Immutable

N.B. Collections.unmodifiableList( List ) Immutable objects -- much easier to reason about; no worrying about changes over time, e.g. some other code entirely mutating a (cached) result of yours

But what drawback? Instead of wanting modify/update a single field, (for immutable) I must copy the entire object. move-ship update-world Much more allocation/copying happening -- performance hit. (But: only a factor of 2x extra memory needed, since we can immediately reclaim (garbage-collect) the previous value that might now be inaccessible)

Cf. C vs Java strings, when calling toUpperCase.

representing N0

Consider the following grammar:

  Expr      ::= Number | Var | ParenExpr | BinExpr | IfZExpr
  ParenExpr ::= ( Expr ) 
  BinExpr   ::= ( Expr BinOp Expr )
  IfZExpr   ::= if Expr is0 then Expr else Expr ;
  BinOp     ::= plus | minus | times

  Number    ::= [any numeric literal, a la Java or Racket, your choice]
  Var       ::= [any string with no whitespace, that is not one of the reserved words “plus”, is0, etc..]
(Not spelled out in the above: Whitespace is required between all terminals/non-terminals, with the exception of punctuation.)

Our project will:

You can use either scheme or java for your project (but you'll be expected to be able to *understand* the code used either way). You'll be provided with a skeleton version to get you started.

How to represent Exprs: Let's start by representing (the parse tree for) “(3 plus 4)” and “((3 plus 4) minus 5)” :

(define-struct/contract 
    (bin-expr [left expr?] [op bin-op?] [right expr?]))

(make-bin-expr 3 'plus 4)
(make-bin-expr (make-bin-expr 3 'plus 4)
               'minus
               5)


; We need data def'ns for our union types;
; we'll make real code out of the union-type-def'n
; (so that we can use it in with 'define/contract', if you want):

(define (expr? any-val)
  (or (number? any-val)
      (string? any-val)
      (paren-expr? any-val)
      (bin-op-expr? any-val)
      (if-Z-expr? any-val)))1
2 

(define (bin-op? any-val)
  (member any-val (list 'plus 'minus 'times)))


1 Rather than calling each function on any-val, we could use map:

    (map (lambda (f) (f any-val))
         (list number? string? paren-expr? bin-op-expr? if-Z-expr?)))
This would give us a big list of booleans (in this case, mostly false with perhaps one true). Then, we could (nearly) use foldl take the or of the entire list:
  (foldl or
         false
         (map (lambda (f) (f any-val))
              (list number? string? paren-expr? bin-op-expr? if-Z-expr?)))
Actually, that doesn't quite work, since or is not a function (it short-circuits, so it's special syntax). But people want to do this all the time, so there is a function ormap:
  (ormap (map (lambda (f) (f any-val))
              (list number? string? paren-expr? bin-op-expr? if-Z-expr?)))
(ormap and andmap are built-in, but you could write them yourself, straight from the design recipe.) Thus a schemer wouldn't think twice about writing:
(define (is-expr? any-val)
  (ormap (map (lambda (f) (f any-val))
              (list number? string? paren-expr? bin-op-expr? if-Z-expr?)))
     

2 Well, if they were concerned about traversing the list twice (once with map, then again with ormap) they'd revert to list-processing, probably using foldl:

(define (is-expr? any-val)
  (foldl (lambda (f found-it) (or found-it (f any-val)))
         false
         (list number? string? paren-expr? bin-op-expr? if-Z-expr?)))
     

homelecturesexamshwsbreeze (snow day)


©2011, Ian Barland, Radford University
Last modified 2011.Oct.28 (Fri)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme