7. Functions & Lambda Expressions

7.1. Basic Function Syntax

  1. In a new Kotlin or Kotlinscript file, write a function named triangleArea that computes and returns the area of a triangle, given the lengths of its three sides as parameters named a, b and c, each of type Double. Add some code that calls the function a few times and prints the computed areas.

    You should use Heron’s formula, which gives the area of a triangle with sides a, b and c as

    \[A = \sqrt{s(s-a)(s-b)(s-c)}\]

    where s is the ‘semi-perimeter’, given by

    \[s = \frac{a + b + c}{2}\]

    In your function calls, experiment with both positional and named argument styles.

  2. Create a copy of the ‘stats’ program from the previous worksheet. Modify it so that it has two functions. The first should read data from a file with a given name into a list, returning that list. The second should compute and return the standard deviation of values in a list. Your functions should be specified as shown below:

    fun readData(path: String): List<Double> {
      ...
    }
    
    fun standardDeviation(data: List<Double>, mean: Double): Double {
      ...
    }
    

    Modify the rest of the program so that it calls these functions, then run it and check that it behaves the same way as it did before.

7.2. Lambda Expressions & Closures

  1. Write some Kotlin code that creates a list of Int values and then filters out any that are less than 0 or greater than 100. Use the filter method to achieve this. Provide it with a lambda expression that will indicate whether a value should be included in or excluded from the output. Add code to print out the original and filtered lists, so that you can verify visually whether your implementation is correct.

  2. Modify the previous exercise, adding the following before the invocation of filter:

    val lowest = 0
    val highest = 0
    

    Then modify the lambda expression, turning it into a closure that binds to lowest and highest instead of using the literal values of 0 and 100. Run the code and make sure that the behaviour is unchanged.

  3. Add some code that transforms the list to a new one in which values less than lowest are made equal to lowest and values greater than highest are made equal to highest. Use the map method to achieve this, with a suitable closure.

    Note: you can do this either as two separate invocations of map, with different closures, or as a single invocation using a single more complicated closure.

    Note also that you can create shorter implementations of the closures using the Math.min and Math.max utility methods, which return the minimum of a pair of values and maximum of a pair of values, respectively.

  4. Add some code to the program that takes values from the original list until a negative value is encountered, putting the taken values into a new list.

    You can do this in one line of code by using the takeWhile method and a suitable lambda expression.

  5. Add some code that groups values from the original list into two new lists, one containing all the negative values and the other containing all the non-negative values.

    Again, this can be done in one line of code, by using the groupBy method and a suitable lambda expression.