Homework 6:
Recursive Functions and Language Processing
Due: Monday, March 4, 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 File
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 or '()
.
The zip file also includes two files that contain helper functions we saw in class. Keep them 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...
-
... any of Racket's primitive higher-order functions, including
map
,apply
, andfilter
. -
...
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 internaldefine
in any function.
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
-
Write a structurally recursive function named
(tails lst)
that takes a list as an argument.tails
returns a list containing all of the sublistslst
, includinglst
. For example:> (tails '(1 2 3)) '((1 2 3) (2 3) (3) ()) > (tails '(a (1 2) c 3)) '((a (1 2) c 3) ((1 2) c 3) (c 3) (3) ())
Think carefully about what the function should return if it receives the empty list as an argument. This is also the base case for the recursion. -
Write a mutually recursive function named
(n-list? obj)
that takes one argument, which can be any Racket value.n-list?
returns true if and only ifobj
is an n-list. For example:> (n-list? '(1 (2 (3 4) 5) 6)) #t > (n-list? '(1 (2 (3 a) 5) 6)) ; oops, there's an 'a #f
n-list?
should be mutually recursive with the functionnum-expr?
, which returns true if its argument is a number expression and false if not.
Even though the argument to this function can be any Racket object, you should still use the definition of n-list to design your function. An n-list must either be an empty list or a pair whosecar
is a number expression and whosecdr
is an n-list. Similarly, use the definition of number expression to designnum-expr?
. Your functions must follow the definitions in order to tell if their arguments do! -
Write a structurally recursive function named
(tree-min bin-tree)
that takes as an argument a binary treebin-tree
of this form:<binary-tree> ::= <number> | (<number> <binary-tree> <binary-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 functionmin
useful here. Note: You do not need an accumulator variable for this problem! You can determine the answer for each case directly from its parts. -
Write a structurally recursive function named
(declared-vars exp)
that takes as input an expression in the little language from class:<exp> ::= <varref> | (lambda (<var>) <exp>) | (<exp> <exp>)
declared-vars
returns a list of all the variables declared inexp
. Recall that onlylambda
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
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
Each case ofdeclared-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 functionappend
. -
Note: This is an extra credit problem. I encourage
you to do it for practice, but it is not required.
Write a structurally recursive function(prefix->postfix exp)
that takes one argument, an expression in the same little language as Problem 4.prefix->postfix
returns an expression of the same form as its argument, except that all function applications have been reversed. For example:> (prefix->postfix '(square x)) '(x square) > (prefix->postfix '(lambda (y) (x y))) '(lambda (y) (y x))
Use the same syntax procedures for the little language described in Problem 4. For this problem, you will also need the constructor functions:make-varref
make-lambda
make-app
Deliverables
By the due time and date, use the course submission system to submit the following files electronically:
-
homework06.rkt
, the source file containing your function definitions -
homework06-tests.rkt
, the source file containing your test cases
Be sure that your submission follows the submission requirements. Be sure to use the specified name for your file. This enables the autograder to find and run your code.