Logo
  • Home
  • Classes
  • Conveying Computing
  • Exams
  • Fractal Gallery
  • Guides
  • Problem Sets
  • Syllabus

PS3 – Comments

Question 1: Is the begin expression necessary? Either explain how to obtain exactly the same behavior as (begin Expr1 Expr2) without using begin, or explain why it is not possible to obtain the same behavior using only the subset of Scheme defined in Chapter 3.

There is no way to define a procedure that has the same behavior as begin. The closest we could come is,
(define (mybegin a b) b)
Then, (mybegin e1 e2) would evaluate to the same value as (begin e1 e2). But, the difference is that with the application expression the subexpressions may be evaluated in any order, but with the begin expression e1 is guaranteed to always be evaluated before e2. This difference would be important if the expressions have side-effects (that is, they do something, instead of just producing a value). For example, (begin (display "Hello ") (display "World!")) would always print out Hello World!, but (mybegin (display "Hello ") (display "World!")) might print out either Hello World! or World!Hello . (With DrRacket it appears to always display Hello World!, but the language evaluation rules do not guarantee that it always must.)

We could rewrite a begin expression without using begin, though. To do so, we need to use expressions that evaluate subexpression in a defined order. We have two choices from the basic Scheme expressions: the if expression (since the predicate is always evaluated first, then one of the consequent or alternate expressions), and the application expression (since all the subexpressions are evaluated before the procedure is applied and the body expression of the procedure is evaluated).

Using if expressions we can transform the begin expression (begin Expr1 Expr2) into:

   (if Expr1 Expr2 Expr2)
(note that Expr2 appears twice, but is only evaluated once. We use it for both the consequent and alternate expression to ensure that whatever Expr1 evaluates to, Expr2 will be evaluated next.

Using application expressions:

   ((lambda (ignore) Expr2) Expr1)
Note that the order is reversed here, since the operaned subexpression will be evaluated before the body expression.

Question 2: By experimenting with DrRacket, try and guess the evaluation rule for a let* expression. (A gold-star quality answer would also attempt to define its semantics more precisely by showing how it can be transformed into an equivalent expression like we did for the let expression.)

With a let expression, each clause is evaluated, but in the original environment (with all the names meaning what they meant before any let clauses were evaluated). With the let* expression, each clause is evaluated in turn, in the environment that results from the previous clauses. So, if the first let* clause associated a value with a name, that is the value associated with this name when the next clause is evaluated. (This answer is a bit vague for now, since we have not formally defined how values are associated with names. We will do this in Chapter 9 and Problem Set 5, and even more precisely in Problem Set 7 and Chapter 11.)

We could transform the non-empty let* expression,

  (let* ((n1 e1)
         rest)
     body)
into:
  (let ((n1 e1))
     (let* (rest)
        body))
Thus, each clause in a let* produces a new nested let.

Question 3: Demonstrate how any if expression can be rewritten as an equivalent cond expression. A convincing demonstration would include a transformation similar to the one we showed for transforming a cond expression into an equivalent if expression, but that transforms an if expression into the equivalent cond expression.

We can transform any if expression:
   (if predicate consequent alternate)
into an equivalent cond expression:
   (cond (predicate consequent)
         (else alternate))

Question 4: Show that (F O(R-60 F) F) is a string in the language defined by our BNF grammar. To do this, you should start with CommandSequence, and show a sequence of replacements that follow the grammar rules that produce the target string. You can use the rule numbers above to identify the rules.

Start: CommandSequence

By rule 1, rewrite CommandSequence ::= ( CommandList ).

By rule 2, replace the CommandList in ( CommandList ) with Command CommandList to get (Command CommandList ).

For the rest of the steps, we will show the rewriting by identifying the rule we use, and underlining the part of the expression that changes.

Rule 4: (Command CommandList) ==> (F CommandList)
         -------                   - 

Rule 2: (F CommandList) ==> (F Command CommandList)
           -----------

Rule 6: (F Command CommandList ==> (F OCommandSequence CommandList)
           -------                    ----------------

Rule 1: (F OCommandSequence CommandList) ==> (F O(CommandList) CommandList)
            ---------------                      -------------

Rule 2: (F O(CommandList) CommandList) 
             -----------                  
        ==> (F O(Command CommandList) CommandList)
                 -------------------

Rule 5: (F O(Command CommandList) CommandList) 
             -------                             
        ==> (F O(RAngle CommandList) CommandList)
                  ------

Rule 7: (F O(RAngle CommandList) CommandList) 
              -----                               
        ==> (F O(R-60 CommandList) CommandList)
                  ---

Rule 2: (F O(R-60 CommandList) CommandList) 
                  -----------                  
        ==> (F O(R-60 Command CommandList) CommandList)
                      -------------------

Rule 4: (F O(R-60 Command CommandList) CommandList) 
                  -------                
         ==> (F O(R-60 F CommandList) CommandList)
                       -
Rule 3: (F O(R-60 F CommandList) CommandList) 
                     -----------
         ==> (F O(R-60 F) CommandList)

Rule 2: (F O(R-60 F) CommandList) 
                     -----------   
         ==> (F O(R-60 F) Command CommandList)
                          -------------------

Rule 4: (F O(R-60 F) Command CommandList)
                     -------                               
         ==> (F O(R-60 F) F CommandList)
                          _

Rule 3: (F O(R-60 F) F CommandList) ==> (F O(R-60 F) F)
                       -----------
Since we were able to produce (F O(R-60 F) F) from CommandSequence by following the replacement rules, we have shown that (F O(R-60 F) F) is a string in the language.

Question 5: It will be useful to have procedures that take L-system commands as parameters, and return information about those commands. Define the following procedures in ps3.rkt: ...

(define (is-forward? lcommand)
  (eq? (car lcommand) 'f))

(define (is-rotate? lcommand)
  (eq? (car lcommand) 'r))

(define (is-offshoot? lcommand)
  (eq? (car lcommand) 'o))

(define (get-angle lcommand)
  (if (is-rotate? lcommand)
      (cdr lcommand)
      (error "Bad attempt to get angle")))

(define (get-offshoot-commands lcommand)
  (if (is-offshoot? lcommand)
      (cdr lcommand)
      (error "Bad attempt to get offshoot commands")))

Question 6: Define a procedure rewrite-lcommands in ps3.rkt that takes a list of L-system commands as its first parameter. The second parameter is a list of L-system commands that should replace every forward command in the first list of commands in the result.

(define (rewrite-lcommands lcommands replacement)
  (flatten-commands
   (map 
    (lambda (command)  
      (if (is-forward? command)
          replacement ; forwards are replaced with replacement 
          (if (is-offshoot? command) 
              (make-offshoot-command
               (rewrite-lcommands 
                (get-offshoot-commands command) 
                replacement))
              (if (is-rotate? command)
                  command ; rotates are unchanged
                  (error "Bad command: " command)))))
    lcommands)))

Question 7:

  1. Define a procedure, vertical-mid-line that can be passed to draw-curve-points so that (draw-curve-points vertical-mid-line 1000) produces a vertical line in the middle of the window.
    (define vertical-mid-line
      (lambda (t) (make-point 0.5 t)))
    
  2. Define a procedure, make-vertical-line that takes one parameter and produces a procedure that produces a vertical line at that horizontal location. For example, (draw-curve-points (make-vertical-line 0.5) 1000) should produce a vertical line in the middle of the window and (draw-curve-points (make-vertical-line 0.2) 1000) should produce a vertical line near the left side of the window.
    (define (make-vertical-line x)
      (lambda (t) (make-point x t)))
    

Question 8: To check you understand everything so far, define a procedure half-line that uses translate, horiz-line and shrink to draw a line half the width of the window that starts in the middle of the display window.

(define (draw-half-line)
  (draw-curve-points (translate (shrink horiz-line 0.5) 0.5 0.5) 1000))

Question 9: Define a procedure num-points that determines the approximate number of t-values that will be used for the nth curve when drawing

 
   (connect-rigidly c1 (connect-rigidly c2 (connect-rigidly curve3 (... cn))))
The first argument to num-points is the number of t-values left. The second argument is the number of curves left.
(define (num-points p n) 
  (if (= n 1) p (num-points (/ p 2) (- n 1))))

Question 10: Fill in the missing code for handling rotate commands (marked as Question 10 in ps3.rkt). You will want to use (rotate-around-origin curve rotate-angle) somewhere in your code to rotate every curve after the rotate command by the rotate-angle.

Question 11: Fill in the missing code for handling offshoot commands (marked as Question 11 in ps3.rkt).

(define (convert-lcommands-to-curvelist lcommands)
  (cond ((null? lcommands)
          (list (lambda (t) 
                   (make-colored-point 0.0 0.0 
                                       (make-color 0 255 0)))))
        ((is-forward? (car lcommands))
          (cons-to-curvelist
           (make-vertical-line (get-distance (car lcommands)))
           (convert-lcommands-to-curvelist (cdr lcommands))))
        ((is-rotate? (car lcommands))
               ;;; Rotate every curve in the rest 
         (let
             ;; L-system turns are clockwise, so use - angle
             ((rotate-angle (- (get-angle (car lcommands)))))
           (map
            (lambda (curve)
              (rotate-around-origin curve (get-angle (car lcommands))))
            (convert-lcommands-to-curvelist (cdr lcommands)))))
        ((is-offshoot? (car lcommands))
         (append
          (convert-lcommands-to-curvelist (get-offshoot-commands (car lcommands)))
          (convert-lcommands-to-curvelist (cdr lcommands))))
        (else (error "Bad lcommand!"))))

Question 12: Define a procedure make-lsystem-fractal in ps3.rkt that takes three parameters: replace-commands, a list of L-system commands that replace forward commands in the rewriting; start, a list of L-system commands that describes the starting curve; level, the number of iterations to apply the rewrite rule.

(define (make-lsystem-fractal replace-commands start level)
  ((n-times
    (lambda (previous-commands)
      (rewrite-lcommands previous-commands replace-commands))
    level)
   start))
Another possibility without using n-times:
(define (make-lsystem-fractal replace-commands start level)
  (if (= level 0)
      start
      (make-lsystem-fractal replace-commands
                            (rewrite-lcommands start replace-commands)
                            (- level 1))))

Question 13: Submit your best fractal image and the code you used to create it. You must submit the "raw" image created by your program. You may also optionally submit a second image that starts from your raw image but can be edited using any image-editing tools you want (e.g., Photoshop). We encourage you to be as creative as possible. Note that you can use draw-lsystem-fractal (etc.), just modify things to make a "new-looking" image. If your image is interesting or beautiful enough, you may receive untold fame and eternal glory by having it be used as the course logo. If your image is really spectacular, your fame may reach Gaussian proportions (or at least approach that of the most famous one-time cs1120 student) when your image is used for the cover of the next edition of the course book!

Visit the Fabulous Functional Fractal Gallery to see the submitted fractals. Some are quite interesting and artistic, but none quite reach the level I want for the next book cover. But, its not too late — you can submit a new fractal at any time by posting it in the Gallery comments.
Print Friendly Print Get a PDF version of this webpage PDF

Leave a Reply Cancel reply

You must be logged in to post a comment.

cs1120 | RSS | Comments RSS | Book | Using These Materials | Login | Admin | Powered by Wordpress