Homework 3:
Higher-Order Functions in Racket

Due: Monday, February 9, at 11:59 PM

Introduction

This assignment gives you your first chance to write and use higher-order functions in Racket.

Template Source File

Download this template file and use it as the starting point for your submission. Please name your file homework03.rkt!

homework03.rkt includes a require expression at the top. It imports the rackunit module and enables you to write test cases for your solutions. The template file contains several test cases for each problem.

homework03.rkt includes a provide expression at the top, which exports your five public functions. This enables users to load your module and run your functions. It also enables me to test your code using my own Rackunit tests.

With provide, you must define all five functions. If you don't have time to solve a problem, leave the template file's placeholder function. It returns a legal default value for the function.

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.

  • Do not use a let expression in any function.
  • Do not use an internal define in any function.
  • Do not use explicit recursion or looping in any function. Your solutions to Problems 3, 4, and 5 should use higher-order functions such as apply and map to do their jobs.

Helpful Functions

You may find these Racket primitives useful on this assignment:

  • string->number converts a string that contains a number into the equivalent number.
  • min takes any number of numeric arguments and returns the smallest.
  • exact->inexact converts an exact number (an integer or a fraction) into the equivalent floating-point number.
  • You may pass a two-argument function to map. If you do, pass two list arguments, not one. map will pass the corresponding items in each list to the function at the same time:
    > (map + '(1 3) '(2 7))
    '(3 10)                    ; 1+2 and 3+7
    
    You do not have to use this, but you may if you think it helps.

Problems

  1. For Problem 3 of Homework 2, you wrote a function named ring-area that computes the area of the ring formed by two concentric circles.

    In manufacturing, we often work in a setting with one of the radii fixed. For instance, we may need to make washers of various sizes that have a fixed-size hole in the middle. In this case, the inner radius rI is fixed.

    Write a Racket function named ring-area-around that takes one number as an argument: the inner radius rI, in inches. ring-area-around returns a function that takes one argument, the the outer radius rO, also in inches. The returned function returns the area of the ring formed by the concentric circles. For example:
    > ((ring-area-around 1) 2)
    9.42477796076938
    
    > (define area-for-2inch-bolt (ring-area-around 2))
    > (area-for-2inch-bolt 5)
    65.97344572538566
    
    I have provided check-= expressions for these examples. Write at least two more check-= expressions to test your solution.
  2. For Problem 5 of Homework 2, you wrote a function named in-range? that tests to see if two values are within a specified tolerance.

    When we work in engineering settings with such tolerances, the epsilon value is often fixed for most of our tests. Passing epsilon to the function every time we call it is inconvenient, but making epsilon a global variable creates bigger problems.

    Write a Racket function named in-range-of? that takes one number as an argument: the epsilon to use as a tolerance. in-range-of? returns as its value a function that takes two number arguments. The returned function returns true if the difference between its arguments is less than epsilon, and false otherwise. For example:
    > ((in-range-of? 0.1) 4.95 5.0)
    #t
    
    > ((in-range-of? 0.1) 5.0 4.95)     ; works both ways
    #t
    
    > (define within-0.01?
          (in-range-of? 0.01))
    
    > (within-0.01? 4.95 5.0)           ; not anymore!
    #f
    
    > (within-0.01? 5.0 4.99)
    #t
    
    I have provided check-true and check-false expressions for these examples. You do not have to write any more tests for this problem.
  3. Suppose that we have a list containing height/weight pairs for a group of people, in inches and pounds, respectively:
    ( (76 . 195) (81 . 212) (79 . 225) (78 . 206) ... )
    
    We would like to know the average weight of the people in the group.

    Use higher-order functions such as map and apply to define a Racket function named average-weight. This function takes a list of height/weight pairs as its only argument and returns the average weight of the group. For example:
    > (average-weight '((79 . 225)))
    225.0
    
    > (average-weight '((70 . 150) (62 . 100)))
    125.0
    
    Assume that we have already written a function named average that takes any number of numeric arguments and returns their average. (It is given in the template code file.) You may write other helper functions if you like, but you do not have to.

    I have provided check-= expressions for these examples. Write at least two more check-= expressions to test your solution.
  4. Suppose that we have a list of scores from the UNI women's basketball team this season. Each score is a list of size two, whose first value is the number of points UNI scored and whose second value is the number of points UNI's opponent scored. For example, after the third game of the season this year, we had:
    ((49 63) (58 62) (41 74) (51 50))
    
    This list contains four games. UNI lost the first three 63-49, 62-58, and 74-41, and won the fourth 51-50.

    The margin of victory in a game is the (positive) difference between the two teams' scores. For Game 1, the margin of victory was abs(49 - 63) == abs(-14) == 14 points. For Game 4, the margin of victory was abs(51 - 50) == abs(1) == 1 point. The list can contain any number of these pairs.

    Write a Racket function named total-margin that takes one argument, a list of this form. The function returns the total of all the margins of victory in the list. For example:
    > (total-margin '((102 51) (78 67) (53 94)))       ;; 51 + 11 + 41
    103
    
    > (define uni-women '((49 63) (58 62) (41 74) (51 50)))
    > (total-margin uni-women)
    42
    
    I have provided check-= expressions for these two examples in your template file. Write at least three more check-equal? expressions to test your solution.
  5. To monitor enrollments each semester, I have a spreadsheet that contains a list of courses with names, enrollments, and capacities. I read the spreadsheet data into a Racket list that looks like this:
    '(("Dept" "Number" "Section" "Class Nbr" "Capacity" "Enrolled")
      ("CS" "1000" "1" "11546" "30" "30")
      ("CS" "1025" "1" "11547" "30" "30")
      ("CS" "1120" "1" "11557" "30" "15")
      ("CS" "1130" "1" "11548" "30" "18")
      ... )
    
    The first item in the list is the header row in the spreadsheet. It is not part of the data.

    The dean and provost frequently ask me for various summary data, such as total enrollments or remaining capacity.

    Write a Racket function named min-open-seats that takes such as a list as its only argument. It returns the minimum number of open seats available in any section. For example:
    > (define example '(...))     ; the data shown above
    > (min-open-seats example)
    0
    
    CS 1000 and CS 1025 both have 30 - 30 = 0 open seats. The other classes have 15 and 12 open seats, respectively.

    I have provided a check-equal? expression for this example. Write at least two more check-equal? expressions to test your solution.

Deliverables

Use Save Definitions to save the file of function definitions you create using the template you downloaded. It will have the file extension rkt. Be sure to use the specified name for your file! This enables the auto-grader to find and run your code.

By the due time and date, use the course submission system to submit the following files electronically:

No hard copy is required.

Be sure that your submission follows the submission requirements.