Homework 6
Recursive Functions and Language Processing

Due: Monday, March 9, at 11:59 PM

Introduction

This assignment asks you to write even more recursive functions in Racket. The goals of this assignment are to gain more experience with common recursion patterns and to begin applying them to programming language topics.

Template Source Files

Download the zipped directory hw06.zip. It contains templates for your solutions and two files of helper functions.

  • homework06.rkt, a template file for your function definitions
  • homework06-tests.rkt, a template file for your test cases
  • syntax-procs.rkt, a file containing syntax procedures for the little language we are studying
  • occurs-procs.rkt, a file containing two functions we wrote for processing expressions in the little language

Please use the given names as the names of the files you submit, and do not modify the provide or require clauses in any of the files.

With provide, you must define all five functions. If you don't have time to solve a problem, define a function that takes the correct number of arguments and returns a legal default value, such as 0, #f, or '().

Keep the two files of helper functions in the folder with your solutions and tests. You will not modify or submit these files.

Do Not Use...

To solve these problems, you do not need any Racket features beyond the things we have learned in class and the things discussed in this assignment. In order to practice the new skills we are learning, do not use...

  • ... any of Racket's primitive higher-order functions, including map, apply, and filter.
  • ... flatten, reverse, or any Racket function that converts a list argument to another datatype. Process the list one element at a time.
  • ... a let expression or an internal define in any function.

You do not need an interface procedure or an accumulator variable to solve any of these problems. You can determine the answer for each case directly from its parts.

Organizing Code

Put your solutions in homework06.rkt. Put any helper functions you write for a problem after the main function of your solution.

Put your tests in homework06-tests.rkt. For each problem, write at least three Rackunit expressions to test your solution. Depending on the type of value that the function produces, use check-equal? or check-true/check-false. You may use my examples as one of your tests. Be sure that you test other key cases, too.

Test only the public functions. Helper functions are not visible outside your solution module.

Data Definitions

The problems refer to these inductive data definitions:

<binary-tree> ::= <number>
                |  (<number> <binary-tree> <binary-tree>)


 <prefix-exp> ::= (<operator> <number-exp> <number-exp>)
 <number-exp> ::= <number>
                | <prefix-exp>


        <exp> ::= <varref>
                | (lambda (<var>) <exp>)
                | (<exp> <exp>)
As discussed in class, use the syntax procedures for the little language. They are defined in syntax-procs.rkt:
exp?
varref?
lambda?   lambda->param   lambda->body
app?      app->proc       app->arg

Problems

  1. Write a structurally recursive function named (tree-min bin-tree) that takes as an argument a binary tree bin-tree.

    tree-min returns the smallest value in the tree. For example:
    > (tree-min '(8 (13 11 (5 24 6)) (15 (12 10 14) 20)))
    5
    
    You will find Racket's primitive function min useful here.
  2. Write a structurally recursive function named (tree-contains? n bin-tree) that takes two arguments, a number n and a binary tree bin-tree.

    (tree-contains? n bin-tree) returns #t if n occurs anywhere in bin-tree, and #f otherwise. For example:
    > (tree-contains? 8 '(7 (12 8 6) (4 3 9)))
    #t
    
  3. Write a mutually recursive function named (count-operators prefix-exp) that takes one argument, a binary expression in prefix notation.

    count-operators returns the number of operators in prefix-exp. For example:
    > (count-operators '(* (+ 4 5) (+ 7 6)))
    3
    
    count-operators must be mutually recursive with the function count-operators-ne, which returns the number of operators in a number expression.
  4. Write a structurally recursive function named (count-lambdas exp) that takes as input an expression in the little language from class.

    count-lambdas returns the number of lambda expressions that appear in exp. For example:
    > (count-lambdas '(f (lambda (x) x)))
    1
    > (count-lambdas '(lambda (x)
                        (lambda (z)
                          z)))
    2
    
  5. Write a structurally recursive function named (declared-vars exp) that takes as input an expression in the little language from class.

    declared-vars returns a list of all the variables declared in exp. Recall that only lambda expressions can create a variable. For example:
    > (declared-vars '(lambda (y) (x y)))
    (y)
    > (declared-vars '((lambda (x)
                            (lambda (z) z))
                          (lambda (x) y) ))
    (x z x)     ;; duplicates are allowed
    
    Each case of declared-vars will return a list of symbols. In the app case, you will need to combine two lists into one. For this, you will want to use Racket's primitive function append.
    > (append '(w x) (y z))
    (w x y z)
    

Deliverables

By the due time and date, use the course submission system to submit the following files electronically:

Be sure that your submission follows the submission requirements. Be sure to use the specified name for your file. This enables the auto-grader to find and run your code.