Docstoc

Programming Languages

Document Sample
Programming Languages Powered By Docstoc
					Programming Languages

      COMP 321
     Spring 2008
     Practicum 5
           Practicum 5
• lists as trees
• tail recursion
• let and letrec
             reference
• reference:
   – Dybvig chapter 2, sections 5-7
                                  recursion
                                   review
• finding the length of a list
      (define length
        (lambda (ls)                       (define list-copy
                                             (lambda (ls)
           (if (null? ls)                       (if (null? ls)
                 0                                    ‘( )
                 (+ (length (cdr ls)) 1)              (cons (car ls)
            )                                            (list-copy (cdr ls)))
          )                                     )
                                             )
      )                                    )
                  Deep Recursion
                     review
finding the number of items in a list (that contains lists)
   example: (1 2 (3 4) 5 (6 (7 8) 9) 10) contains 10 items.
Note that pair? Returns false if a list is empty.
      (define numItems
        (lambda (ls)
          (if (null? ls)
              0
              (if (or (null? (car ls)) (pair? (car ls))
                 (+ (numItems (car ls)) (numItems (cdr ls)))
                 (+ (numItems (cdr ls)) 1)
               )
            )
          )
      )
             Lists as trees
• Can represent a list as a tree:
     (a (b c d) ((e f) g))

   a         (b c d)           ((e f) g)

         b      c      d   (e f)       g

                           e       f
                                recursion
• tree-copy treats the structure of pairs as a tree rather
  than as a list
   – left subtree is car, right subtree is the cdr
   – builds a new tree, leaves the leaves alone
      (define tree-copy
        (lambda (tr)
           (if (not (pair? tr))                (tree-copy ‘((a . b) . c))
                 tr
                 (cons (tree-copy (car tr))
                       (tree-copy (cdr tr)))
           )
        )
      )
                   Lists as trees
• procedure depth takes a list item as arg and returns
  depth of the tree

  (define depth
     (lambda (item)
        (if (not (pair? item))
             0
             (max (add1 (depth (car item))) (depth (cdr item))))))

• max is a built-in procedure
                        Lists as trees
• procedure flatten takes a list ls as arg and returns a list of all the
  leaves

    (define flatten
       (lambda (ls)
          (cond
             ((null? ls) ‘())
             ((pair? (car ls))
                   (append (flatten (car ls))(flatten (cdr ls))))
              (else (cons (car ls)(flatten (cdr ls)))))))

•   append is a built-in procedure; takes two lists and combines into one list
                   Lists as trees
• flat recursion is over the top-level items of a list
   – equivalent to recursion over the nodes of the corresponding
     tree, where the nodes are one level below the root.
• deep recursion is over all items of a list
   – equivalent to recursion over the leaves of the tree
                 Tail recursion
• Consider the factorial procedure below
  (define fact
     (lambda (n)
        (if (zero? n)
           1
           (* n (fact (sub1 n))))))
                 Tail recursion
• when fact is applied to a number, like 3, a return table is built
   – must wait for the return value from the recursive call to finish this
     call
   – when reach base case, work backwards, filling in the table. Called
     backward substitution

   answer1 is (* 3 answer2)
   answer2 is (* 2 answer3)
   answer3 is (* 1 answer4)
   answer4 is 1
                   Tail recursion
• another way of looking at the table (the recursive calls and the
  returns):

   (fact 3)
   (* 3 (fact 2))
   (* 3 (* 2 (fact 1)))
   (* 3 (* 2 (* 1 (fact 0))))
   (* 3 (* 2 (* 1 1)))
   (* 3 (* 2 1))
   (* 3 2)
   6
                 Tail recursion
• to find the factorial of n, must perform n + 1 invocations and
  will have n + 1 rows in the return table.
• for every call to fact must
   – create the return table
   – perform backward substitution
• This is space and time expensive!
• Better type of recursion:
   – change the solution so that you do not have to do any
     computation when the recursive call returns
   – then do not need either a return table or backward
     substitution
   – this is called an iterative process or tail-recursion
                     Tail recursion
•   changing fact to a tail recursive procedure
     – need a helper function.
     – need another variable to accumulate the value of the result

     (define fact-it
        (lambda (n acc)
           (if (zero? n)
               acc
               (fact-it (sub1 n) (* acc n)))))

     (define fact
        (lambda (n)
           (fact-it n 1)))
           let expressions
                review
• variables and let expressions
     (let ((x 1))
       (let ((x (+ x 1)))
          (+ x x)
        )
     )
  (let ((x 1))
       (let ((new-x (+ x 1)))
          (+ new-x new-x)) )
      procedures in let
• lambda expression in let

  (let ((double (lambda (x) (+ x x))))
      (list (double (* 3 4))
             (double (/ 99 11))
             (double (- 2 7))) )
                      closure
• Consider the procedure:
     (define addb
             (let ((b 100))
                      (lambda (x)
                             (+ x b))))
• There are 3 parts to the lambda
  expression:
  – The list of prameters
  – The body of the lambda expression (+ x b)
  – The nonlocal environment in which the lambda
    was defined (the let expression in this case)
                          bindings
• Local bindings always take precedence over global
  or other nonlocal bindings:

      (define a 5)
      (add1 a)
      6
      (let ((a 3))
                 (add1 a))
      4
      (add1 a)
      6
      (let ((a 5))
                 (display (add1 a))
                 (let ((a 3))
                     (display (add1 a)))
                 (add1 a)))
      6
      4
      6
                        bindings
•   In general, the let expression

      (let ((var1 val1) (var2 val2) … (varn valn)) body)

•   is equivalent to

      ((lambda (var1 var2 … varn) body) val1 val2 … valn)
                          bindings
• Local bindings always take precedence
  over global or other nonlocal bindings:

     (define a 10)
     (define b 2)
     (let ((a (+ a 5)))
               (* a b))
    30
     ??

     (let ((a 10)(b 2))
               (let ((a (+ a 5)))
                   (* a b)))
    30
     ??
                         closure
• Local bindings always take precedence
  over global or other nonlocal bindings:

     (define addb
        (let ((b 100))
               (lambda (x)
                  (+ x b))))

     (let ((b 10))
         (addb 25))

     125
      ???
                        closure
• A closure includes the environment in
  which the procedure was defined:

     (let ((b 2))                                b       2
         (let ((add2 (lambda (x) (+ x b)))
                (b 0.5))                         environment 1
            (/ b (add2 b))))

    (/ 0.5 2.5) or 0.2
     ???
                                    procedure (x) (+ x b) Env 1

                                             b       0.5

                                             environment 2
                        closure
• the procedure is still defined within
  environment 1; add2 does not know about
  the second definition of b:
                                                   b       2
     (let ((b 2))
         (let ((b 0.5)                             environment 1
                (add2 (lambda (x) (+ x b))))
            (/ b (add2 b))))
                                    procedure (x) (+ x b) Env 1
    (/ 0.5
     ???     2.5) or 0.2
                                               b       0.5

                                               environment 2
               local functions
• can define a local function

     (define getEven
        (lambda (ls)
           (let ( (evenNum
                    (lambda (x)
                       (zero? (remainder x 2)))) )
              (if (null? ls)
                  ‘()
                  (if (evenNum (car ls))
                         (cons (car ls) (getEven (cdr ls)))
                         (getEven(cdr ls))))
              )))
               local functions
• Problem: local function cannot be recursive, since
  it does not know its own name

      (define fact
         (lambda (n)
            (let ( (fact-it
                    (lambda (k acc)
                       (if (zero? k)
                           acc
                           (fact-it (sub1 k) (* k acc))))) )
              (fact-it n 1)
              )))
            local functions
• Solution: a special type of let called letrec

     (define fact
        (lambda (n)
           (letrec ( (fact-it
                (lambda (k acc)
                   (if (zero? k)
                      acc
                      (fact-it (sub1 k) (* k acc))))) )
            (fact-it n 1)
            )))
                     (test1 20)
                       functions
              local(test2 20)
                     30

  • Letrec functions 25 their local environment
                      get
                     (test3 20)
    from the letrec that’s being defined.
                     25
(define test1           (define test2           (define test3
 (let ((x 10))           (let ((x 10))           (let ((x 10))
 (lambda (y)             (lambda (y)             (lambda (y)
   (let ((x 5)             (letrec ( (x 5)         (letrec ((test4
        (test2                  (test3                   (lambda (n)
         (lambda (n)             (lambda (n)               (+ n x)))
           (+ n x))))              (+ n x))))           (x 5) )
     (test2 y)))))           (test3 y)))))           (test4 y)))))