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.
-
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 '()
.
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...
-
... 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
(list-index s los)
that takes two arguments, a symbol and a list of symbols.list-index
returns the 0-based first occurrence ofs
inlos
. Ifs
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. -
Write a structurally recursive function named
(tree-sum bin-tree)
that takes as an argument a binary treebin-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. -
Write a structurally recursive function named
(tree? exp)
that takes one argument, which can be any Racket expression.(tree? exp)
returns true ifexp
is abin-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 anor
expression with two parts. -
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 ifv
is declared as a variable anywhere inexp
and never used. Recall that onlylambda
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 calloccurs-free?
. Have your source file require theoccurs-procs.rkt
file from class. -
Don't forget that applications and
lambda
expressions may containlambda
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:
-
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 auto-grader to find and run your code.