PK - Chapter 5 Flashcards

1
Q

What is a higher order function ?

A

A higher order function does one, or both, of the following:

  • accepts another function as a parameter
  • returns a function as its return value
fun foo(firstParam: String, someFunction: (String) -\> String) {
 println(someFunction(firstParam))
}
fun bar(firstParam: String): (String) -\> String = {
 println("The first parameter is $firstParam")
}

foo(“FIRST”, bar() )

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Why would you want a function
to return another function ?

A

There are 2 common reasons to have
a function return another function:

  • you might want to initialize a function variable
    in more than one place
  • you might want the function to use a when
    to determine which function would be appropriate
    to use based on current state
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Create a variable that
contains a function.

A

val isEven: (Int) -> Boolean = modulo(2)
OR
val isEven: { k: Int -> k % 2 == 0 }

listOf(1,2,3,4,5,6).filter(isEven)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is a closure ?

A

A function that has access to variables
and parameters defined in outer scopes.
It is said that they “close over” these
variables.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is an anonymous function ?

A
  • It looks similar to a normal function
    definition, except the name is omitted
    fun(a: String, b: String) : String = a + b
  • If the parameter type(s) can be inferred,
    then that can also be omitted
    fun(a) = a % 2 == 0
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is a top-level function ?

A
Top-level functions are defined outside
the scope of a class or interface.
fun isEven(k) = k % 2 == 0
val intList = listOf(1,2,3,4,5,6)
intList.filter { isEven(it) }
// OR
intList.filter(::isEven)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Create an extension function
on Int that identifies an odd number.

A
fun Int.isOdd() = this % 2 != 0
val intList = listOf(1,2,3,4,5,6)
intList.filter { it.isOdd() }
// OR
intList.filter(Int ::isOdd)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Create an extension function
on Int that returns a to the power of b.

A
fun foo(a: Double, b: Double,
 f: (Double, Double) -\> Double) = f(a,b)
foo(2.0, 3.0, { a, b -\> Math.pow(a,b) })
// OR
foo(2.0, 3.0, Math.pow)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Explain a bound function reference.

A
  • a function reference that is bound
    to a particular instance
  • created by placing an expression
    before the “::” operator
  • this allows us to eliminate an argument
    to the function

fun String.equalsIgnoreCase(other: String) =
this.toLowerCase() == other.toLowerCase()

val stringList = listOf("foo", "bar", "baz", "buz")
stringList.filter("bar"::equalsIgnoreCase)
// Instead of
stringList.filter { (String:equalsIgnoreCase) ("bar", it) }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Explain a function-literal receiver.

A
  • a function with a parameter defined
    to accept a receiver when invoked
  • the receiver is provided inside the
    body of the function
fun foo(fn: String.() -\> Boolean) {
 var someBoolean = "some string".fn()
 ...
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Explain inline functions ?

A
  • functions introduce overhead because:
    • they are instances of objects, so
      they require an allocation in the heap
    • there are additional method invocations
      to invoke the function
  • the inline keyword generates the bytecode
    at the call site, eliminating the allocation in
    the heap and the additional method invocations
  • the savings in overhead is most impactful in loops
  • the cost is in the additional amount of code
    generated, versus avoiding many allocations
    in a tight loop
  • an inline function cannot be asigned to an
    inlined variable
  • many standard library functions are inline

inline fun foo() { }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is noinline and
when would you use it ?

A
* sometimes you do not want a
 function to be inlined
* typically used when creating an
 inline higher-order function, but
 you don't want a function parameter
 to be inlined

inline fun foo(noinline fn: (Int) -> Boolean) { }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Explain function currying.

A
  • currying is the process of transforming
    a function that accepts multiple parameters
    into a series of functions, each of which
    accept a single function
  • currying is a technique that allows functions
    with multiple parameters to work with other
    functions that only accept single arguments
  • related to the concept of partial appliction,
    where not all parameters are specified in
    advance, returning a new function that
    accepts the missing parameters
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Why is function currying useful?

A
  • when some parameters are available
    in the current scope, but not every scope
  • when some parameters are available
    in the current scope, but not all of them
  • to reduce the arity of a function, to match
    a lower arity input type of another function
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the arity of a function ?

A

The number of parameters.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Provide an example of
function currying.

A
fun compute(logger: (String) -\> Unit) : Unit { }
fun logger(level: Level, appender: Appendable, message: String) : Unit { }

Without currying:
fun compute { message -> log(Level.Warn, Appender.Console, message) }

With currying:
val myLogger = ::logger.curried() (Level.SEVERE) (System.out)
fun compute(myLogger)

17
Q

Explain memoization.

A
  • a technique for speeding up function calls
  • caches and reuses output instead of
    recomputing for a given set of inputs
  • offers a trade-off between memory and speed
  • appropriate for computationally intensive,
    recursive or highly iterative functions
fun memoize(fn: (A) -\> R) : (A) -\> R {
 val map = ConcurrentHashMap()
 return { a -\>
 map.getOrPut(a) {
 fn(a)
 }
 }
}

val memquery = memoize(::query)

18
Q

What is a type alias ?

A
  • create a new type that is an
    alias for an existing type
  • useful as a logical replacement
    for complex type signatures
  • there is no overhead or performance
    penalty
  • can type alias inner classes
  • type aliases must be defined at the
    top level

typealias String1 = String

19
Q

What is either ?

A
  • many functional programming languages
    have a type called Either
  • Either is used to represent an object
    with 2 possible types
  • Kotlin does not have a standard Either
    object, but one can be created

sealed class Either<out></out>

Left<out> (value: L) : Either<l>() { }<br></br>class Right<out> (value: R) : Either<nothing>() { }</nothing></out></l></out>

20
Q

Explain sealed classes.

A
  • another form of enumeration, specifying which subclasses can extend the sealed class; restricted hierarchies
  • subclasses of the sealed class must be declared in the same file
  • subclasses can be extended anywhere, depending on scoping
  • sealed classes cannot be instantiated directly, only through a subclass
  • elegant when used with a “when is” as an expression
21
Q

Explain declaration-site variance.

A
  • in and out are variance annotations
  • out versus in versus no variance annotation
  • out - can only be generated/returned by the class
  • ClassB<subtypeofx> can extend ClassB<x></x></subtypeofx>
  • in - can only be consumed by the class