Homework 9
Last updated: Fri, 8 Dec 2023 15:20:46 -0500
Out: Mon Dec 04, 2023, 00:00 EST
Due: Sun Dec 10, 2023, 23:59 EST
Overview
In this assignment, we’ll use the "CS450js Lang" to write recursive programs!
This hw will be graded as follows:
correctness (10 pts)
design recipe (25 pts)
style (15 pts)
README (1 pts)
Setup
Create a new repository for this assignment by going to the CS450 Fall 2023 GitHub Organization page and clicking "New".
Name the repository <YOUR ACCOUNT NAME>-hw9 where <YOUR ACCOUNT NAME> is your GitHub account name.
For example, if my GitHub account is cs450student then I would name my hw9 repository cs450student-hw9.
Mark the repository as Private.
Check "Add a README file".
Add a .gitignore file for "Racket" to automatically ignore temporarily files.
When done click "Create repository".
Starter Code
Here is a hw9 starter repo. It contains hw9.rkt, which has some starter code in it.
Submitting
1 Before Submitting
Do not submit until all code has been thoroughly tested, independent of the autograder (if there is one), and you are reasonably sure the assignment is complete and correct.
The autograder is not a software development tool so it should not be used as one.
If you submit and get an autograder error, this means the code you wrote is not complete and correct and it’s up to you to figure out why.
The course staff is here and eager to help, of course, but cannot do so without details about what has already been tried. (For example, "why is the autograder giving an error?" is not something we can help with.)
The grading criteria (i.e., test suite) is subject to change. This means that the grade on the preliminary autograder test suite (if one is provided) is not the final grade.
2 Common Problems
Common submission problems:
a required identifier is not provided or defined in the homework file
an external file has not been uploaded to GitHub
the code is in an infinite loop, e.g., do not start a big-bang loop automatically when running a file. (Instead, it should be in a main function)
3 Files
A submission must have the following files in the repository root:
hw9.rkt: Contains the hw solution code. This file should use the "CS450js Lang". In other words, you should have #lang s-exp "cs405js-lang.rkt" (see start repo) at the top.
No provides are needed (or possible in the language!), so for this assignment, examples and tests should all be in this file.
tests.rkt: This file should require hw9.rkt and define tests for it. For this assignment, tests should be included in hw9.rkt.
README.md: Contains the required README information, including the GitHub repo url.
Also, the repository must have appropriate commit messages. See How to Write a Git Commit Message if you are unsure how to write a commit message.
4 GradeScope
When ready, submit this assignment to GradeScope using the "GitHub" submission feature with your hw9 repository selected.
Submission link: GradeScope HW9
HW Tasks
For this assignment, use the "CS450js" Programming Language to write five recursive functions:
;; fac : Nat -> Nat ;; Computes factorial of the input ;; filt : (X -> Boolean) List<X> -> List<X> ;; Standard list filter function ;; qsort : List<Int> -> List<Int> ;; Sorts the given list of ints, in ascending order, functionally (no mutation, not in-place) ;; gcd : Nat Nat -> Nat ;; Computes the greatest common divisor of the inputs using Euclid's algorithm. ;; sierpinski : Nat -> 2htdp/Image ;; Draws a Sierpinski (fractal) triangle of the specified depth.
Each function must follow the design recipe and include all required components. In particular, structurally recursion functions should follow their data definitions, while generative (non-structural) recursive functions should follow the Generative Recursion Recipe. Don’t forget to include a Termination Argument in the latter case.
- The syntax of the language follows this 450jsExpr data definition:
450jsAtom
Interp: an atomic value (see data def below)
Variable
Interp: a variable reference
(list ’bind [Variable 450jsExpr] . 450jsExpr)
Interp: defines a variable bound to the Result of first expression. This variable is in-scope while running the second expression only.
(list ’bind/rec [Variable 450jsExpr] . 450jsExpr)
Interp: defines a variable bound to the Result of first expression. This variable is in-scope while running both the first and second expression.
(list ’fn List<Variable> 450jsExpr)
Interp: a "lambda" function expression
(list ’iffy 450jsExpr 450jsExpr 450jsExpr)
Interp: if expression, where the test follows JS "truthy" semantics (see hw7 for details)
(cons 450jsExpr List<450jsExpr>)
Interp: function application
Variables are Symbols and a 450jsAtom is a:Number
String
SymBool
A SymBool is:’realtrue
’realfalse
- Running a program in this language should produce one of the following 450jsResult:
(Racket) Number
(Racket) String
(Racket) Boolean
(Racket) cons value
NaN
450jsFunctionResult
450jsErrorResult
A 450jsFunctionResult is a(Racket) Function
(fn-result List<Symbol> 450jsAST Environment)
A 450jsErrorResult is a(undefined-err Symbol), Interp: undefined variable error
(arity-err 450jsFunctionResult List<450jsResult>), Interp: the specified application has an invalid number of arguments
(apply-err 450jsResult), interp: tried to apply a non-function
(circular-err Symbol), interp: tried to use the named circular reference (from bind/rec
An Environment is a list of Variable and EnvVal pairs, as given in lecture. - The runtime behavior of the language should be as expected from lecture, with a few differences:
The "body" bind and bind/rec can be multiple expressions (hence the "rest" arg in the 450jsExpr data def above). The result of running these expressions, however, is only the result of running the last expression in the body.
A chk=? primitive, mapped to check-equal? from rackunit is available. Combined with the above, this allows you to write a series of tests in the body of each bind and bind/rec and you should write your examples and tests this way.
Errors propagate. In other words, if an applied function evaluates to an error, then the whole function application evaluates to that error. This is true for function positions, arguments, and the "test" position in iffy.
+ appends lists together when all the arguments are lists. when given a mix of lists and strings, the list elements are converted to strings and then "joined" together with commas (test it for yourself in JS!). otherwise, it follows the JS semantics from Homework 7.
- The automatic coercions also follow the JS semantics from Homework 7 with the exception of SymBool -> string conversions which are as follows
realtrue -> "true"
realfalse -> "false"
In addition to the auto-converting functions from hw7 +, -, ==, here is a list of additional primitives in the INIT-ENV initial environment, and the Racket function it’s associated with: * : *, / : /, mk-lst : list, cns : cons, fst : first, rst : rest, emp : empty, < : <, > : >, <= : <=, >= : >=, lrger : max, smller : min, mod : remainder, add1 : add1, sub1 : sub1
Here are the 2htdp/image primitives in INIT-ENV: above : above, beside : beside, triangle : triangle
As usual:
Concise code is readable code (most of the time). This means that any extraneous code negatively affects readability, so get rid of it!
This is bad programming practice because (1) it decreases your ability to understand the code you are writing, and (2) it tends to leave extraneous code in the program, which kills readability (and shows that you don’t understand the code you are writing —
not good!). For this assignment, any extraneous code in the program may result in large deductions. Related to above, this means that you should not include broken, commented out code in the submitted program. (Obviously, Design Recipe components in comments should remain.)
Also, related to above, do not include explicit Code Templates in the submitted program. Templates are for your own benefit to help write functions. They also help you cleanly split larger functions into smaller ones. But you dont need to leave an explicit copy in the code (it’s obvious if you followed the template or not).
Examples should help readability and be carefully selected to help explain the behavior of the functions. (They cannot be the same as the tests.) I will look to these to try to understand the code.
Tests must thoroughly test correctness. Make sure tests include both correct and error-producting programs. In this assignment, any missed corner cases may also result in large deductions.
Just "trying to get the code working" will not earn a good grade on this assignment.
You may update existing Data Definitions (or create new ones) first, before starting to write any code. At this point in the semester, since we are no longer creating small programs, it’s unlikely that the assignment can be completely without focusing and understanding the data representations first.
All other steps of the design recipe—
e.g., name, description, signature, examples, and tests— must also be followed and will also be crucial towards successful completion of this assignment. Functions should be split properly so that each performs "one clear task". One way to know when this is the case is if the function is easy to name and explain concisely. Another way is if a function only processes one kind of data.