1

I'm trying to learn functional programming in Kotlin and am having difficulty making this code work:

import java.util.*

fun caseName(br: String, c: Int): String {
  if (c == 0) {
    return br.toLowerCase()
    } else {
    return br.toUpperCase()
    }
}
fun mapIt(ns: ArrayList<String>, f: (String, Int) -> String): List<String> {
  val coll: List<String> = ns.map {it -> f(it, _)}
  return coll
}

fun main(args: Array<String>) {
  val names = arrayListOf("Joe", "Bill", "Murrary")
  val cased = mapIt(names, (::caseName)(_, 0))
  println(cased.first())
}

How do I get mapIt to recognize the case flag when mapping over the list?

Thank you!

EDIT: The case above is a simplified version of the following, which does not work either...

data class Borrower(val name: String, val maxBooks: Int) {
    companion object {

        fun getName(br: Borrower, c: Int): String {
          if (c == 0) {
            return br.name.toLowerCase()
            } else {
            return br.name.toUpperCase()
            }
        }

        fun findBorrower(n: String, brs: ArrayList<Borrower>, f: (Borrower) -> String): Borrower? {
            val coll: List<Borrower> = brs.filter { it -> f(it) == n }
            if (coll.isEmpty()) {
                return null
            } else return coll.first()
        }
    }
}

fun main(args: Array<String>) {
    val br1 = Borrower(name = "Borrower1", maxBooks = 1)
    val br2 = Borrower(name = "Borrower2", maxBooks = 2)
    val br3 = Borrower(name = "Borrower3", maxBooks = 3)
    val br4 = Borrower(name = "borrower4", maxBooks = 4)
    val br5 = Borrower(name = "BORROWER5", maxBooks = 5)
    val brs1 = arrayListOf(br1, br2, br3, br4, br5)

    val c = Borrower.findBorrower("borrower3", brs1, {Borrower.Companion::getName(it, 0)})
    println(c)
}
0

2 Answers 2

5

There are a couple of issues here:

  1. Your objectives are contradictory here - you want mapIt to take a 2-arg function, but it also looks like you're trying to perform a partial application of caseName, which would of course result in a 1-arg function.

  2. Underscores don't do what you think in Kotlin (it looks like maybe you come from a Scala background?).

It looks like you want something either like this:

// f is a *single*-arg function
fun mapIt(ns: ArrayList<String>, f: (String) -> String): List<String> {
    return ns.map(f)
}

fun main(args: Array<String>) {
    val names = arrayListOf("Joe", "Bill", "Murrary")
    val cased = mapIt(names, { caseName(it, 0) })  // Partial application
    println(cased.first())
}

or like this:

// f is a two-arg function
fun mapIt(ns: ArrayList<String>, f: (String, Int) -> String): List<String> {
    return ns.map { f(it, 0) }
}

fun main(args: Array<String>) {
    val names = arrayListOf("Joe", "Bill", "Murrary")
    val cased = mapIt(names, ::caseName)
    println(cased.first())
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your help. Yes I do have some Scala experience but was using the underscores here as a means to describe the holes in my knowledge! I was after the single-arg function and see the error in my thinking - missed the partial application. Would you mind looking at my edit - which inspired the simplified example that I began with? I believe there is a companion object issue? Thank you.
1

Your original code (the Borrower one) is actually very close to success, so I'm going to ignore your werid simplified version. You just got one line wrong:

val c = Borrower.findBorrower("borrower3", brs1, {Borrower.Companion::getName(it, 0)})
                                                                    ^^
                                                        Why you are using double colon?

The last parameter is a lambda expression, and it just make no sense to use a function reference inside a lambda, even in scala. Just use plain dots and it will be fine.

val c = Borrower.findBorrower("borrower3", brs1, {Borrower.Companion.getName(it, 0)})

Since members of companion objects can be called with just the main types' name, it can be further simplified into

val c = Borrower.findBorrower("borrower3", brs1, {Borrower.getName(it, 0)})

1 Comment

I was using "::" because I thought I had to call a Bound Class Reference. Thank you both for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.