any-cs-in-b?
which we developed in
class today.
We started with these data definitions, examples, templates, and signature and purpose for the function. All of this information will be used to answer subsequent questions.
;; a Course is a (make-course symbol number symbol number number) (define-struct course(dept coursenum term sections seats)) ;; Examples (make-course 'CS 1101 'C 6 25) (define MA2201 (make-course 'MA 2201 'A 8 30)) ;; a ListOfCourse is either ;; empty, or ;; (cons Course ListOfCourse) ;; Examples (define sched1 (cons MA2201 (cons (make-course 'CS 1101 'C 6 25) empty))) #| ;; course-template: Course ... -> ... ;; ... (define (course-template acourse ...) (course-dept acourse) (course-coursenum acourse) (course-term acourse) (course-sections acourse) (course-seats acourse)) |# #| ;; ListOfCourse template ;; loc-fcn: ListOfCourse ... -> ... ;; ... (define (loc-fcn aloc ...) (cond [(empty? aloc) ] [(cons? aloc) (course-template (first aloc) ...) (loc-fcn (rest aloc) ...)])) |# ;; any-cs-in-b?: ListOfCourse -> Boolean ;; consumes a list of courses and determines whether any CS courses are offered in B-term
A: any-cs-in-b? consumes a ListOfCourse. There are two ways to create a ListOfCourse (look at the data definition). So I know I need at least two test cases, one for an empty list and one for a cons list.
Q: What kind of data does the function produce? (look at the signature).
A: any-cs-in-b? produces a Boolean. I know the answers that my check-expect should produce will be either true or false. I know at the minimum I need a test case that produces true and a test case that produces false. Here are the test cases I start with:
(check-expect (any-cs-in-b? empty) false) (check-expect (any-cs-in-b? (cons (make-course 'CS 1101 'C 5 20) (cons (make-course 'CS 2301 'B 3 24) empty))) true)Q: Should I have any other test cases? (look at the purpose).
A: Yes. I need a non-empty list of courses that doesn't have any CS courses in B-term. I need a list that contains at least one course offered in B-term that is not a CS course. These two additional cases with what I already have should be sufficient. Notice that with these test cases I'm taking advantage of using the examples I developed up above.
(check-expect (any-cs-in-b? sched1) false) (check-expect (any-cs-in-b? (cons MA2201 (cons (make-course 'ECE 3801 'B 5 30) empty))) false)
A: any-cs-in-b? consumes a ListOfCourse. This tells me I need to use the ListOfCourse template. Here is the template with the changes made to the function name, and the ...'s removed in the function heading and recursive function call:
;; any-cs-in-b?: ListOfCourse -> Boolean ;; consumes a list of courses and determines whether any CS courses are offered in B-term (define (any-cs-in-b? aloc) (cond [(empty? aloc) ] [(cons? aloc) (course-template (first aloc) ...) (any-cs-in-b? (rest aloc))]))Q: What should the function produce in the empty? case? (look at the check-expect's you wrote, and look at the function's purpose).
A: It should produce false, because a list with no courses in it can't have any courses that are CS courses offered in B-term.
Almost always, the hardest part of designing a function involves figuring out how to combine the pieces the template gives you into an expression that correctly solves the problem. Let's look at the cons? part of the template:
[(cons? aloc) (course-template (first aloc) ...) (any-cs-in-b? (rest aloc))]
A: Here's the recursive call:
(any-cs-in-b? (rest aloc))It will process every course in the rest of the list, and return true only if at least one course in the rest of the list is a CS course in B-term. If none of the courses in the rest of the list meet that criteria, the recursive call will return false.
Q: What else does any-cs-in-b? need to know in order to produce the correct answer? (look at the purpose)
A: It needs to know if the first course in the list is a CS course offered in B-term.
Q: How can I figure out if the first course in the list is a CS course offered in B-term? (look at the loc-template)
A: The ListOfCourse template suggests that I should develop a helper function to answer this question. The helper function will consume a Course (the data type of (first aloc) is a Course).
We've determined that we need to develop a helper function that consumes a Course. Use the course-template:
;; course-template: Course ... -> ... ;; ... (define (course-template acourse ...) (course-dept acourse) (course-coursenum acourse) (course-term acourse) (course-sections acourse) (course-seats acourse))
A: We know the helper will consume a Course. We don't need the helper to consume any other information, because the selectors for a Course will provide the information we need.
Q: What should the helper produce?
A: We know we want the helper to figure out if the course is a CS course offered in B-term. If it is, the helper should return true, and otherwise it should return false. So the helper should produce a Boolean.
Q: What is the purpose of the helper?
A: It consumes a Course, and returns true if the course is a CS course offered in B-term, and returns false otherwise.
Q: What should I name the helper function? (look at signature/purpose)
A: cs-in-b? is a name that reflects the purpose of the function
Here's the template with the signature and purpose filled in, the correct name of the function, and the ...'s removed:
;; cs-in-b?: Course -> Boolean ;; consumes a course, and produces true if the course is a CS course offered ;; in B-term, otherwise it produces false (define (cs-in-b? acourse) (course-dept acourse) (course-coursenum acourse) (course-term acourse) (course-sections acourse) (course-seats acourse))
At this point we're back to asking questions about test cases. cs-in-b? consumes a Course, and there is only one way to make a Course. The function produces a Boolean, so I know I should have at least two test cases, one that produces true and one that produces false. Upon further thought, I realize I need to provide at least 4 test cases: a CS course in B-term, a CS course not in B-term, a non-CS course in B-term, a non-CS course not in B-term. Here are the test cases:
(check-expect (cs-in-b? (make-course 'CS 2301 'B 3 20)) true) (check-expect (cs-in-b? (make-course 'CS 1101 'C 5 25)) false) (check-expect (cs-in-b? (make-course 'MA 2201 'B 8 30)) false) (check-expect (cs-in-b? (make-course 'MA 2201 'A 8 30)) false)Q: What pieces of the template do I need, and what pieces can I delete? (look at the purpose)
A: The function only needs to look at the course's department and term, so delete the other selectors from the template:
;; cs-in-b?: Course -> Boolean ;; consumes a course, and produces true if the course is a CS course offered ;; in B-term, otherwise it produces false (define (cs-in-b? acourse) (course-dept acourse) (course-term acourse)
Q: What are the data types of (course-dept acourse) and (course-term a-course)? (look at the data definitions)
A: They're both symbols. I need to see if the dept is 'CS and if the term is 'B, so I need to use symbol=?:
;; cs-in-b?: Course -> Boolean ;; consumes a course, and produces true if the course is a CS course offered ;; in B-term, otherwise it produces false (define (cs-in-b? acourse) (symbol=? (course-dept acourse) 'CS) (symbol=? (course-term acourse) 'B) )
Q: How can I combine the two booleans that are returned by the two calls to symbol=? (look at the purpose of cs-in-b?)
A: Use and. I want cs-in-b? to return true only if BOTH the course is a CS course, and it is offered in B-term.
;; cs-in-b?: Course -> Boolean ;; consumes a course, and produces true if the course is a CS course offered ;; in B-term, otherwise it produces false (define (cs-in-b? acourse) (and (symbol=? (course-dept acourse) 'CS) (symbol=? (course-term acourse) 'B) )At this point, run the test cases on cs-in-b? and make sure it works.
We're back to the list function, any-cs-in-b? But now we have a helper function cs-in-b? that is fully designed and tested. Here's the list template with the name of our new helper function:
;; any-cs-in-b?: ListOfCourse -> Boolean ;; consumes a list of courses and determines whether any CS courses are offered in B-term (define (any-cs-in-b? aloc) (cond [(empty? aloc) false ] [(cons? aloc) (cs-in-b? (first aloc)) (any-cs-in-b? (rest aloc))]))
A: It produces a Boolean that will be true only if the first course in the list is a CS course offered in B-term.
Q: What type of data does (any-cs-in-b? (rest aloc)) give us, and what does it represent?
A: It produces a Boolean. We answered this question earlier. Here's what we said: It will process every course in the rest of the list, and return true only if at least one course in the rest of the list is a CS course in B-term. If none of the courses in the rest of the list meet that criteria, the recursive call will return false.
Q: How can I combine the two booleans produced by any-cs-in-b? and cs-in-b? (look at the purpose of any-cs-in-b?)
A: Use or. We want the function to produce the answer true if either the first course in the list meets our criteria, or if any of the course in the rest of the list meet our criteria.
;; any-cs-in-b?: ListOfCourse -> Boolean ;; consumes a list of courses and determines whether any CS courses are offered in B-term (define (any-cs-in-b? aloc) (cond [(empty? aloc) false ] [(cons? aloc) (or (cs-in-b? (first aloc)) (any-cs-in-b? (rest aloc)))]))
Run the test cases on any-cs-in-b?, and we're done. Whew!