Homework 5:
More Structurally Recursive Functions

Due: Monday, February 26, at 11:59 PM

Introduction

This assignment asks you to write a few more recursive functions in Racket. Its primary goal is to gain experience with common recursion patterns, especially mutual recursion.

Template Source File

Download these files:

and use them as the starting points for your submission. As usual, please use the names given for your files.

The source file includes a provide clause that exports your five public functions for use by other files. The tests file includes a require clause that imports your functions, enabling it (and you!) to test them with Rackunit. The provide clause also enables me to test your code using my own Rackunit tests.

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 '(). homework05.rkt includes default functions for each problem that you can use until you write your code.

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

Use a comment to indicate where the code for each problem begins and ends. The template already does that for you.

Put your tests in homework05-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.

Put any helper functions you write for a problem between the main function in your solution and the tests for the main function. (You are not required to write any helper functions.)

Problems

  1. Write a structurally recursive function named (prefix-of? lst1 lst2) that takes two arguments, both flat lists. Either can be the empty list. prefix-of? returns true if lst2 starts with the items in lst1 in the same order, and false otherwise. For example:
    > (prefix-of? '(cs1510 cs1800) '(cs1510 cs1800 cs1520 cs1410))
    #t
    > (prefix-of? '(cs1510 cs1800) '(cs1510 cs1520 cs1800))
    #f
    
    The empty list is a prefix of every other list.

  2. Write a mutually recursive function named (includes-course? course requirements) that takes two arguments, a symbol course and a course tree requirements. A course tree is defined as:
    <course-tree> ::= ()
                    | (<course-exp> . <course-tree>)
    
     <course-exp> ::= <symbol>
                    | <course-tree>
    
    includes-course? returns true if course occurs anywhere in requirements, and false otherwise. For example:
    > (includes-course? 'cs1510
                        '((cs1120 cs1130 cs1140 cs1150 cs1160 cs1510)
                          cs1520
                          ((cs1410 cs2420) (cs1800 cs2530))))
    #t
    > (includes-course? 'cs3540
                        '(cs1120 cs1130 cs1140 cs1150 cs1160 cs1510))
    #f
    
    includes-course? should be mutually recursive with the function includes-course-ce?, which processes a course and a course-exp.

  3. Write a mutually recursive function named (nlist+ nlist) that takes one argument, an n-list nlist.
        <n-list> ::= ()
                   | (<number-exp> . <n-list>)
    
    <number-exp> ::= <number>
                   | <n-list>
    
    nlist+ returns the sum of the numbers in nlist. For example:
    > (nlist+ '(1 -1 1 7 21 -6 21 3 4 -5 1))
    47
    > (nlist+ '(1 -1 (1 (7 21)) ((-6 21) 3 (4 -5) 1)))
    47
    
    nlist+ should be mutually recursive with the function num-expr+, which returns the sum of the values in a number expression.

  4. Write a mutually recursive function named (max-length str-list) that takes one argument, a string-list.
    <string-list> ::= ()
                    | (<string-exp> . <string-list>)
    
     <string-exp> ::= <string>
                    | <string-list>
    
    max-length returns the length of the longest string in str-list. If str-list is the empty list, it returns -1. For example:
    > (max-length '("Write" "a" "mutually" "recursive" "function"
                    ("max-length" "str-list")
                    "that" "takes" "one" "argument"
                    ("a" "string-list")))
    11
    
    max-length should be mutually recursive with the function max-length-se, which processes a string expression.

    Recall that Racket provides the functions max and string-length.

  5. Write a mutually recursive function named (prefix->infix binary-exp) that takes one argument, a binary expression in prefix notation.
    <prefix-exp> ::= (<operator> <number-exp> <number-exp>)
    <number-exp> ::= <number>
                   | <prefix-exp>
    
    prefix->infix returns an equivalent infix expression as its value.
     <infix-exp> ::= (<number-exp> <operator> <number-exp>)
    <number-exp> ::= <number>
                   | <infix-exp>
    
    In both kinds of expression, an operator is a symbol. For example:
    > (prefix->infix '(+ 4 5))
    '(4 + 5)
    
    > (prefix->infix '(* (+ 4 5)
                         (+ 7 6)))
    '((4 + 5) * (7 + 6))
    
    prefix->infix should be mutually recursive with the function number-expr->infix, which returns an infix version of a number expression.

    Note: This is a fine place to use program derivation, if you like. You are not required to do so.

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. As always, be sure to use the specified name for your files. This enables the autograder to find and run your code.