Homework 6
Recursive Functions and Language Processing

Due: Monday, March 10, 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.

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 or '().

Keep the two files of helper functions in the folder with your solutions and tests. You will not 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...

Organizing Code

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

As before, 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.

Problems

  1. Write a structurally recursive function (list-index s los) that takes two arguments, a symbol and a list of symbols. list-index returns the 0-based first occurrence of s in los. If s does not occur in the list, it returns -1. For example:
    > (list-index 'd '(a b c d e f d))
    3
    
    Hint: You will need an interface procedure for this problem.

  2. Write a structurally recursive function named (tree-sum bin-tree) that takes as an argument a binary tree bin-tree of this form:
    <binary-tree> ::= <number>
                    |  (<number> <binary-tree> <binary-tree>)
    
    tree-sum returns the sum of all the values in the tree. For example:
    > (tree-sum '(1 (2 3 4) 5))
    15
    > (tree-sum '(8 (13 11 (5 24 6)) (15 (12 10 14) 20)))
    138
    
    Note: You do not need an accumulator variable for this problem! Simple structural recursion is your friend.

  3. Write a structurally recursive function named (tree? exp) that takes one argument, which can be any Racket expression. (tree? exp) returns true if exp is a bin-tree as defined for Problem 2, and false otherwise. For example:
    > (tree? '1)
    #t
    > (tree? '(8 (13 11 (5 24 6)) (15 (12 10 14) 20)))
    #t
    > (tree? 'x)                                          ; not a number
    #f
    > (tree? '(1 (2 3 4) (2 3 4 5)))                      ; too many items in a tree
    #f
    > (tree? '(8 (13 x (5 24 6)) (15 (12 10 14) 20)))     ; contains non-number
    #f
    
    This is your second type predicate. Follow the datatype for this problem! There are two possible cases, so your function should be an or expression with two parts.

  4. Write a structurally recursive function named (unused-var? v exp) that takes as input a symbol and an expression in the little language from class:
    <exp> ::= <varref>
            | (lambda (<var>) <exp>)
            | (<exp> <exp>)
    
    unused-var? returns true if v is declared as a variable anywhere in exp and never used. Recall that only lambda expressions can declare a variable. For example:
    ; x is declared and not used
    > (unused-var? 'x '(lambda (x) y))
    #t
    
    ; x is declared *and* used
    > (unused-var? 'x '(lambda (y) (lambda (x) x)))
    #f
    
    ; ... but y is declared and not used
    > (unused-var? 'y '(lambda (y) (lambda (x) x)))
    #t
    
    ; here, x is declared and used in the app's argument
    > (unused-var? 'x '(a (lambda (z) (lambda (y) (lambda (x) x)))))
    #f
    
    As discussed in class, use the syntax procedures for the little language defined in syntax-procs.rkt:
    exp?
    varref?
    lambda?   lambda->param   lambda->body
    app?      app->proc       app->arg
    
    Two quick notes:
    • unused-var? will need to know if a variable does not occur free in an expression, so it should call occurs-free?. Have your source file require the occurs-procs.rkt file from class.
    • Don't forget that applications and lambda expressions may contain lambda expressions. But then, if you follow the BNF description, you already know that!

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.