Homework 7:
Syntactic Abstractions
Due: Monday, March 25, at 11:59 PM
Introduction
For this assignment, you will write a function to translate a syntactic abstraction into its core form, a few functions to implement a new data type, and one function to do static analysis of programs in our little language. The assignment should help you begin to feel more comfortable with the idea of syntactic abstraction and get more practice working with the little language.
Template Source Files
Download the zipped directory
hw07.zip
.
It contains:
-
homework07.rkt
, a template file for your homework solutions -
syntax-procs.rkt
, a file containing syntax procedures for the little language
Please use the given names for the files, and do not modify the
provide
or require
clauses in either file.
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 '()
.
Organizing Code
As before, you will extend
homework07.rkt
with the code you write for this assignment. Be sure to update
the header block with your personal information. Put any helper
functions you write for a problem after the main function of your
solution.
You do not have to write Rackunit tests for the functions you write. However, I strongly encourage you to evaluate your code using the examples I give in the assignment and to think of other cases that test your functions.
The Little Language
For Problem 5, you will work the little language we saw for the first time in Session 12, processed in Session 13, and extended in Session 16.
<exp> ::= <varref> ; core | (lambda (<var>) <exp>) ; core | (<exp> <exp>) ; core | (let (<exp> <exp>) <exp>)
The core language consists of variable references, lambda expressions, and applications. The full language contains the core features plus local variables ("let" expressions), which are a syntactic abstraction.
Note that any function that processes an expression in the core language should consider only three cases: variable references, lambda expressions, and applications.
A Set Data Type
When doing static analysis, we sometimes need to keep track of a set of symbols. For example, we might want to determine the set of all variable references in a program.
We can use a Racket list to implement a set as a list with no duplicates. The order of the items in a set does not matter.
<set-of-symbols> ::= () | (<item> . <set-of-symbols>)
Using a Racket list of symbols provides us with a lightweight implementation of sets. All we need to do is to implement set operations as functions that process lists of symbols in a way that preserve the meaning of those operations for sets. You will write five such functions for Problems 2,3, and 4, to build sets and test membership.
Problems
-
Write a structurally recursive function named
(curry exp)
that takes one argument, a Racketlambda
expression with n ≥ 1 formal parameters.curry
returns a curried function.
For example:> (curry '(lambda (x) anything)) '(lambda (x) anything) > (curry '(lambda (x y z) anything)) '(lambda (x) (lambda (y) (lambda (z) anything)))
curry
does not process the function body, which can be any Racket expression.
Hint: Makecurry
an interface procedure that passes the parameter list and the body to a structurally recursive helper function that processes the parameter list, which is a list of symbols. Note: you do not need to pass the symbollambda
to the helper! That is a constant the helper can insert on its own. -
Define three short non-recursive functions that
implement basic set membership for
the set datatype described above:
-
(empty-set)
, which takes no arguments and returns an empty set as its value. In our implementation, an empty set is simply an empty list. (Yes, this is a simple function!) -
(set-member? sym S)
, which takes two arguments, a symbolsym
and a set of symbolsS
.set-member?
returns true ifsym
is inS
, and false otherwise. -
(set-add sym S)
, which takes two arguments, a symbolsym
and a set of symbolsS
.set-add
returns a set containingsym
and all of the symbols inS
, with no duplicates.
> (empty-set) '() > (set-member? 'a (empty-set)) #f > (set-member? 'a '(x y z)) #f > (set-member? 'y '(x y z)) #t > (set-add 'a '(x y z)) '(a x y z) > (set-add 'y '(x y z)) '(x y z)
You will find the primitive functionmember
helpful for implementing both of these functions:-
It does the same task as
set-member?
, except that it returns a list when it finds the item.set-member?
always returns#t
or#f
. -
In
set-add
, you can use it to determine ifS
already containssym
before adding it withcons
.
-
-
Write the recursive constructor function
(set-union S1 S2)
, which takes as arguments two sets of symbols,S1
andS2
.set-union
returns a set containing all of the items in bothS1
andS2
, with no duplicates.
For example:> (set-union '(a b) '(x y z)) '(a b x y z) > (set-union '(a x y z b) '(x y z)) '(a b x y z)
To implementset-union
, useset-add
from Problem 2 to recursively add each item fromS1
toS2
. -
Write the recursive membership function
(set-subset? S1 S2)
, which takes as arguments two sets of symbols,S1
andS2
.set-subset?
returns true if every member ofS1
is inS2
, and false otherwise.
For example:> (set-subset? '(a b) '(x y z)) #f > (set-subset? '(x y z) '(a x y z b)) #t
To implementset-subset?
, useset-member?
from Problem 2 to recursively check to see if each item ofS1
is a member ofS2
. -
Write a structurally recursive function named
(free-vars exp)
that takes as input an expression in the core little language, and returns a set of all of the variables that occur free in expression.
For example:> (free-vars 'x) '(x) > (free-vars '(square x)) '(square x) > (free-vars '(lambda (y) (x y))) '(x) > (free-vars '((lambda (y) (y (square x))) (lambda (y) (f f)))) '(square x f) > (free-vars (preprocess '(let (a b) (let (c (lambda (d) a)) (c a))))) '(b)
Use the functions you wrote for Problems 2 and 3 in your solution, whenever you need to create an empty set, add an item to a set, or find the union two sets.
You will probably also want to use Racket's primitiveremove
function. It removes the first occurrence of an item from a list. Because the lists we pass it here are sets, removing the first occurrence of a symbol removes the only occurrence!
As always, you must use the same syntax procedures for the little language. I have added syntax procedures for the newlet
expression and updated theexp?
type predicate.
Deliverables
By the due time and date, use the course submission system to submit the following files electronically:
-
homework07.rkt
, the source file containing your function definitions
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.