Kotlin and Functional Programming

Kotlin

In this homework you will write some short, but perhaps not always simple, programs in Kotlin to get you more familiar with using the language and doing everything without loops or variables (the start to functional programming).

I strongly encourage you to write and test in little pieces. For instance, in the final program, be sure you are clear about what the add function does with a MutableList. Functional programming encourages you to thing "bottom up" so start as small as you can and build on really small pieces.

Throughout this assignment you may not use loops or variables. By loop, I mean any construct like a for or while loop, that causes an action to be repeated within a function (this definition is intended to allow recursion.) By variable I mean any object whose value may change by means of assignment. So an object allocated with "val" would not be a variable as its value, once set, the pointer cannot be changed.

Associated with each part are one or more questions -- in bold face. Answer these questions in your README.

Part 1

Write a hello world program that takes a single parameter from the command line, tries to interpret that paramameter as an integer, and if an integer, prints "hello world" that many times. Do this without any variables or loops.

Do not put the tailrec tag onto your function (yet).

What is the largest number of time you can print "hello world" without getting a "stack overflow" exception.

Adjust your program by adding the keyword "tailrec" to the first line of the recursive function. (Also, make your function tail recursive if it was not already. That is, if the function was

    BEFORE
        fun printHW(va: Int) {
    AFTER
        tailrec fun printHW(va: Int) {
    
Does adding "tailrec" change the "stack overflow" limit? What is the limit after adding "tailrec"?

Nested Functions

Consider the following main function which allocates 3, 2-dimensional arrays.
    fun main() {
        val arr = arrayOf(arrayOf(1, 2, 3), arrayOf(4, 5, 6), arrayOf(7, 8, 9))
        val arrc = arrayOf(arrayOf('c', 'd', 'e'), arrayOf('g','h','i'), arrayOf('j','l','m','n'))
        val arrs = arrayOf(arrayOf("c", "d", "e", "A"), arrayOf("g","h","i"), arrayOf("j","l","m","n", "1", "2", "3"))
        
        printArr(arr)
        printArr(arrc)
        printArr(arrs)
    }    
Write the printArr function that is called by main such that the output is:
1 2 3 
4 5 6 
7 8 9 

c d e 
g h i 
j l m n 

c d e A 
g h i 
j l m n 1 2 3 
Requirements for the printArr function. Having written printArr once, write it again; name the new vesion something clever like printArrV2. This time, use only one recursive function rather than the two you used in the first version. That is, you should not have a nested recursive function.

Which version of printArr do you consider to be "better"? Why? (There is no correct answer.)

Functions that return functions

Write a function that returns a function which computes a number raised to the nth power. So, given following main function
    fun main() {
        val pow4 = nthpower(4)
        println(pow4(2))
        println(pow4(3))
        println(pow4(4))
        println(pow4(5))
    
        println(nthpower(5)(2))
        println(nthpower(8)(2))
    }    
then (assuming that there are no other print statements) the output of this program would be:
    16
    81
    256
    625
    32
    256  
Some requirements:

What is in the closure of the returned function?

Filtering

Kotlin includes, as a method of lists, a method named filter. This method takes a single arguement which is a function that returns a boolean. When applied to a list, filter retuns a new list composed of only those items in the original list for which the function returns true. For instance, here are several versions of a complete program for filtering odd numbers. These programs differ only in the way that the function passed to filter is defined.
fun main() {
    val ll = listOf(1,2,3,4,5,6,7,8,9)
    println(ll.filter(isOdd) )
}
val isOdd = fun (n:Int) : Boolean {
    return (n%2!=0)
}
V2:
    fun main() {
        val ll = listOf(1,2,3,4,5,6,7,8,9)
        println(ll.filter(isOdd) )
    }
    val isOdd = { n:Int -> (n%2!=0) }    
V3:
    fun main() {
        val ll = listOf(1,2,3,4,5,6,7,8,9)
        println(ll.filter{ n:Int -> (n%2!=0) } )
    }    
The version of this that does not work (and is not shown) is where the isOdd function is defined in the way you are most used to. I.e. fun isOdd(va:Int) : Boolean { ... } Write you own implementation of filter that works only in lists of Int. Your implementation should have the following signature.
    fun myFilter(funcc: (Int) -> Boolean, lst:List<Int>) : List<Int> {
That is, your myFilter function should take two arguements:
  1. a function that returns a boolean
  2. a list of integers
You myFilter function should return a list of integers.

Also, write at least 3 different filtering methods. One of these can be isOdd from above. The other two should be for your own creation.

You may add args with default values to your myFilter function if you find it convenient. Your implementation should not use the Kotlin filter function; it must use recursion. Your function may use MutableList and the add function of that class.

Once you have myFilter working, write a generic version with the following signature

    fun <Q> myFilterGeneric(funcc: (Q) -> Boolean, lst:List<Q>) : List<Q> {
Again, you may add params with default values.

For your generic filter, write at least two filtering methods, that work on two different data types. In your main function, include code showing each of these filters in use.

When you submit, submit both the generic and integer only versions of this function. For each you should have a main method that shows your function in operation.

What To Hand in

Copies of the following programs:

Electronic Submissions

Your submission will be handed in using the submit script.

If you write your program on computers other than those in the lab, be aware that your program will be graded based on how it runs on the department’s Linux server, not how it runs on your computer. The most likely problem is not submitting everything or hard coding file locations that are not correct on the Linux servers.

Make a README

Once you have finished coding (and fully commenting your code) make a README file. This file should follow the format of this sample README. This is your opportunity to tell me what went well or poorly, what is still broken and why, etc. I will read, and often respond to, everthing you write in the README.

The easiest place to write your readme is within VSC. Make a file just like any other file but name it README.txt then just write in it. You should start by copying the sample readme.

Submit

If you developed this program on your own computer, you should be able to use the systems set up in lab to help get files to Linux. If you did not get SFTP set up within VSC then do the following:

  1. Open a terminal window on your computer (a windows powershell or a Mac terminal)
  2. Connect to a linux lab machine. A full list of possibly available lab machines is at Machine list. I will assume you are using goldengate.cs.brynmawr.edu -- you can use any machine. To connect:
                                ssh YOURNAME@goldengate.cs.brynmawr.edu
                                    or
                                ssh goldengate
                           
    Enter your Unix password if/when prompted
  3. On the linux computer:
                                 cd cs245
                                 mkdir a3
                           
    You can change a3 to whatever you like, the directions below assume a1.
  4. Leave this terminal window open and connected to Linux, you will use it again in a couple of steps
  5. Within VSC open a terminal by going to the Terminal menu and selecting "new terminal"
  6. In the Terminal inside of VSC you should be in the directory containing your program. Enter
                                 scp * YOURNAME@goldengate.cs.brynmawr.edu:cs245/a3
                           
  7. You should get messages on screen showing that each file in this directory has been copied. Make sure you get all of the files you want to submit.
  8. Confirm that the copy was successful. Back in the Terminal you opened on the Linux machines (in the first steps)
                                 ls a3
                           
    This should show a list of of the files copied in your scp command.
  9. When all of the files are in the a1 directory and you are still in the cs245 directory
                                 /home/gtowell/bin/submit  -c 245 -p 3 -d a3
                           
    This says to submit for project 3 (-p) everything in the directory a1 (-d) for the class 245 (-c). You should see listing of all the files you submitted and a message that says "success".
  10. You can submit multiple times. I will grade only the last submission -- unless you tell me otherwise. The submission process attaches a timestamp so I know when you submitted (down to the second). The closest submission I have ever received to the deadline is 7 seconds.

The submission should include the following items:

README:
This file should follow the format of this sample README
Source files
All of them
Question answers
If separate from readme.
Data files used:
Be sure to include any non-standard data files uses. (Rare)
DO NOT INCLUDE:
Data files that are read from the class site. Do include any of your own data files.

Again: Once you have everything you want to submit in the a3 directory within /home/YOU/cs245/

  1. Go to the directory /home/YOU/cs245
  2. Enter /home/gtowell/bin/submit -c 245 -p 3 -d a3
If this worked you will get a message with the word "success". If you cannot achieve success and the deadline is approaching, send me email. We can set up a meeting to work out your problems. The email will establish that you intended to submit. Once you send the email, do not change the files that you were trying to submit.