1

I am an absolute beginner in functional programming and Kotlin, trying to solve exercises that I created from questions I'm asking myself; my current question being "How to put in practice functional programming onto real world applications using a Ports and Adapters architecture?"

Currently learning about the Either monad, I have the following function in which Perhaps<T> is just a renamed Either<Err, T> for use with exception handling.

This function takes a RequestModel containing arbitrary HTTP parameters, and may Perhaps return a CountBetweenQuery which is just a data class containing two LocalDate.

private fun requestCountBetweenQueryA(model: RequestModel): Perhaps<CountBetweenQuery> {
    return try {
        Perhaps.ret(CountBetweenQuery(extractLocalDateOrThrow(model, "begin"), extractLocalDateOrThrow(model, "end")))

    } catch (e: UnsupportedTemporalTypeException) {
        Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)

    } catch (e: DateTimeException) {
        Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
    }
}

private fun extractLocalDateOrThrow(it: RequestModel, param: String): LocalDate =
        LocalDate.from(DateTimeFormatter.ISO_DATE.parse(it.parameters.first { it.key == param }.value))

In an OO language, I would refactor this so that exception handling either way below in a common exception handler, or higher above (where duplicated code is extracted into a single method). Naturally, I want to turn my extractLocalDateOrThrow into a perhapsExtractLocalDate as part of my exercise:

private fun perhapsExtractLocalDate(it: RequestModel, param: String): Perhaps<LocalDate> = try {
    Perhaps.ret(LocalDate.from(DateTimeFormatter.ISO_DATE.parse(it.parameters.first { it.key == param }.value)))

} catch (e: UnsupportedTemporalTypeException) {
    Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)

} catch (e: DateTimeException) {
    Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
}

I have struggled for an hour trying to figure out how to call the constructor of CountBetweenQuery while preserving the continuation passing style.

This is what I came up with:

private fun requestCountBetweenQueryB(me: RequestModel): Perhaps<CountBetweenQuery> {
    val newCountBetweenQueryCurried: (begin: LocalDate) -> (end: LocalDate) -> CountBetweenQuery =
            ::CountBetweenQuery.curried()

    return Perhaps.ret(newCountBetweenQueryCurried)
            .bind { function -> perhapsExtractLocalDate(me, "begin").map(function) }
            .bind { function -> perhapsExtractLocalDate(me, "end").map(function) }
}

At first I had expected to use return and apply because the two method calls perhapsExtractLocalDate are independent, therefore I would use an applicative style. Instead I was unable to figure out how to avoid using bind, which is from my understanding implies a monadic style.

My questions are:

  • If my understanding is correct, how can I turn this into applicative style?

  • Are there any gross mistakes made in the implementations above? (i.e. idioms, misuse of currying)

Hay
  • 2,246
  • 20
  • 30

1 Answers1

2

I believe I understood what was wrong.

In FP examples written in a proper functional programming language, applicative style is written like someFunction map a apply b but in Kotlin, because we are dealing with methods of objects, this is written in the reserve order when reading from left to right, but in the correct order in terms of argument evaluation. This confused me very much.

private fun requestCountBetweenQueryC(me: RequestModel): Perhaps<CountBetweenQuery> {
    val newCountBetweenQueryCurried: (begin: LocalDate) -> (end: LocalDate) -> CountBetweenQuery =
            ::CountBetweenQuery.curried()

    val a = perhapsExtractLocalDate(me, "begin")
    val b = perhapsExtractLocalDate(me, "end")

    return b.apply(a.map(newCountBetweenQueryCurried))
}

If my understanding is correct, this is also known as the lift2 function.

Hay
  • 2,246
  • 20
  • 30