CS-140 Lab 10 -- First Class Functions

This week, we have been learning about how Java has entered the world of functional programming, treating functions as first class citizens. In today's lab, we will implement some of that knowledge.

In class, we used an example of functional programming by describing the map method, which takes an array and a function as an argument, and applies the function to each element of the array to produce a result. Today, we are going to investigate a couple of different methods which take functions as arguments. The first is a method which produces a sequence of numbers, where the function describes how to get the next element of the sequence. We will look at several variations of sequence generators. We will also investigate a reduce method, which collapses an array into a single result by applying a function to each element of the array.

Getting Started

Create a lab10 package, and create a class called XmpFunc. This class does not need a constructor or any fields, we are using it as a container to hold our static methods. We will make several methods, as follows:

  1. public static double[] sequence(double init,Function<Double,Double> fn,int count)

    This method takes three arguments; an initial value, a function that takes a Double value as an argument, and returns a Double value as a result, and an integer count. This function should create an array of doubles that has count elements, and put the initial value in the first element. Then for the remaining elements in the array, determine the value of the next element by applying the fn function to the previous element. Return the complete array, once you have filled in all count elements. Refer to Lecture 17 Slide 30 for an example of how to do this.

    Before continuing, let's test this method. In the main method, invoke the sequence method with arguments 1.0, a lambda expression which adds 1 to its argument, and the number 10. Use the Arrays.toString method to print the result. Try various different values for the initial value, the function argument, and the count to see what happens. For instance, what if you add 2 instead of 1, or multiply by 2 and add 1? What happens if you take the reciprocal of the argument? What about 1/(1+x)?

  2. A sequence is nice, but some sequences depend not only on the previous entry, but also on the index of the new entry. Can we make a sequence generator that follows these rules? To do so, you will need a function argument that takes two parameters, and produces a single result. The prototype of such a method would be:
    public static double[] indexSequence(double init,BiFunction<Integer,Double,Double> fn,int count)

    Code this method, and add some invocations of the method in your main function. For instance, if you just add the index to the previous member, you get a sequence of 2n - 1. If you multiply the index by the previous value, you get a sequence of factorials.

  3. Finally, create a reduce method. The reduce method should take an array argument, a function (two arguments and one result), and an initial value. Then the function obtains a result by starting the answer with the initial value, and stepping through the array, creating the next answer by applying the function to the previous answer and a single element from the array. After stepping through the array, you will have the final answer. The prototype for the reduce method will be:
    public static double reduce(double[] array,BiFunction<Double,Double,Double> fn,double init).

    Try the reduce function with simple addition to find the sum of an array. Try with multiplication to find the product. Try some other alternatives as well.

Extra Credit

It can be argued that an indexSequence can be used to generate a simple sequence because indexSequences are just generalized forms of sequences. Can you code an invocation of indexSequence that produces an array with the numbers [1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0]? (There are many many ways to do this.)

The Fibonacci sequence is a famous sequence of numbers where each element is the sum of the previous two elements. Can you code a method called biSequence that takes two initial values as arguments, along with a BiFunction and a count, and applies the function to the previous two values to get the next value? Then if you invoke this with biSequence(1,1,(x,y)->(x+y),10), you will get the first ten elements of the Fibonacci sequence.

Can you write a one-line instruction in your main code to calculate the sum of the first 10 elements in the Fibonacci sequence? (I came up with 143.)

Grading Criteria

Zip your code in the lab10 package, and submit it on myCourses. This lab is worth 10 points. You will get the full 10 points if your code compiles without warnings, and produces the correct output. The CA's have their own "main" function that invokes your methods with some pre-defined arguments. The following are reasons for deductions: