CSC 533: Organization of Programming Languages
Spring 2024

HW4: Clojure Functions


For this assignment, you are to define a collection of Clojure functions. For simplicity, place all your function definitions in a single file named LASTNAME-hw4.clj, where LASTNAME is your last name. Be careful to name your functions exactly as defined in the exercises, and be sure to comment each function as to its behavior.

Fun with Geometry

    Recall the following formulas from your high school geometry class:

  1. Define a function named area-rectangle that takes two inputs, the height and width of a rectangle, and returns the area of that rectangle. For example, (area-rectangle 4 7) should evaluate to 28.
  2. Define a function named area-square that takes one input, the length of the side of a square, and returns the area of that square. Since a square IS_A rectangle, your area-square function should call area-rectangle as opposed to duplicating the multiplication. For example, (area-square 6) should evaluate to 36.
  3. Define a function named area-circle that takes one input, the radius of a circle, and returns the area of that circle. For example, (area-circle 10) should evaluate to 314.1592653589793. Note that the constant PI is defined in the Java Math library, so you can access that value in Clojure as java.lang.Math/PI.
  4. Define a function named area-triangle that takes two inputs, the base and height of a triangle, and returns the area of that triangle. For example, (area-triangle 4 10) should evaluate to 20.
  5. Define a function named distance that takes two inputs, lists representing points, and returns the distance between those points. For example, (distance '(0 0) '(3 4)) should evaluate to 5.
  6. Define a function named slope that takes one input, a pair of points representing a line, and returns the slope of that line. For example, (slope '((0 0) (2 4))) should evaluate to 2.
  7. Define a predicate function named parallel? that takes two inputs, each a pair of points representing a line, and returns whether those lines are parallel (i.e., have the same slope). For example, (parallel? '((0 0) (2 4)) '((1 1) (3 5))) should evaluate to true.

List Processing

    Consider the following recursive function, which counts how many negative numbers there are in a list of numbers.

        (defn count-neg [numlist]
          (cond (empty? numlist) 0
                (neg? (first numlist)) (inc (count-neg (rest numlist)))
                :else (count-neg (rest numlist))))       
    
  1. Define a similar function named count-between that takes three inputs, a list of numbers and the low and high numbers of a range, and returns a count of numbers from the list that fall within the specified range (inclusive). For example, (count-between '(1 4 7 12 5 10 19) 5 10) should evaluate to 3.
  2. Define a function named remove-neg that takes one input, a list of numbers, and returns a copy of the list with all negative numbers removed. For example, (remove-neg '(-9 15 0 -1 16 -99)) should evaluate to (15 0 16).
  3. Define a similar function named remove-between that takes three inputs, a list of numbers and the low and high numbers in a range, and returns a copy of the list with all numbers from the specified range removed. For example, (remove-between '(5 1 4 7 12 5 5 10 19 5) 5 10) should evaluate to (1 4 12 19).
  4. Define a function named has-consec-dupes? that takes one input, of list of arbitrary values, and returns whether that list has consecutive duplicates. In other words, it returns true if there are two identical values next to each other in the list, otherwise it returns false. For example, (has-consec-dupes? '(:foo :bar :bar :biz)) should evaluate to true, while (has-consec-dupes? '(:foo :bar :biz :bar)) should evaluate to false.
  5. Define a function named has-dupes? that takes a sortable list (i.e., a list of numbers, Strings or keywords) and returns whether that list has any duplicate values in it regardless of position. For example, (has-dupes? '(4 2 3 1)) should evaluate to false while (has-dupes? '(:foo :bar :biz :bar)) should evaluate to true. Hint: the built-in sort function takes a sortable list and returns a list with those values in sorted order. In a sorted list, any duplicates will have to be consecutive.

Simulations

    The following function simulates the roll of two six-sided dice and returns the sum of those rolls.

        (defn dice-roll []
          (+ (+ 1 (rand-int 6)) (+ 1 (rand-int 6))))      
    
  1. Define a function named count-rolls that takes two inputs, both positive integers, representing a number of rolls and a desired dice total. The function should repeatedly call the dice-roll function to simulate the specified number of rolls and return the number of times the desired total was obtained. For example, the call (count-rolls 1000 7) should simulate 1000 dice rolls and return the number of times 7 was rolled. Since the number of rolls could be large, your function should utilize tail-recursion.
  2. Define a function named inc-index that takes two inputs, a list of numbers and a non-negative integer representing an index. The function should return the list with the number at that index incremented. For example, the call (inc-index '(0 0 0) 1) should return (0 1 0). Since the size of the number lists will likely be fairly small, your solution may utilize full-recursion.
  3. Define a function named count-all-rolls that takes one input, a positive integer, representing a number of rolls. The function should repeatedly call the dice-roll function to simulate that many rolls and return a list with the counts for all dice totals. For example, the call (count-all-rolls 10000) might return (288 526 824 1093 1388 1708 1413 1115 811 563 271), signifying that 288 rolls totaled 2, 526 rolls totaled 3, 824 rolls totaled 4, etc. Since the number of rolls could be large, your function should utilize tail-recursion. Note: you should be able to make use of your inc-index function here.