Functional Hangman in Kotlin with Arrow (part 2)
Tags: kotlin, functional, arrowkt
Published: 2018-12-25 18:59:28

---
title: Functional Hangman in Kotlin with Arrow (part 2)
published: true
tags: kotlin,functional,arrowkt
canonical_url: http://lordraydenmk.github.io//2018/functional-hangman-in-kotlin-with-arrow-part-2/
---

Converting a [Functional Hangman](/2018/functional-hangman-in-kotlin-with-arrow) game from Scala (ZIO) to Kotlin (with Arrow) was a nice exercise. I enjoyed working on it and I learned a lot. When I asked for feedback on the [#arrow](https://kotlinlang.slack.com/messages/C5UPMM0A0/) channel, one of the maintainers, [Leandro](https://twitter.com/mLeandroBF) had an interesting suggestion. Instead of hard-coding the data type `IO` I should try and make the program polymorphic and use `Kind` instead. That means writing the code focusing on the domain logic, using abstractions, and deferring the decision for the concrete data type like `IO` or `Single` (from RxJava) until the main function.

# The journey

I was not familiar with that style of programming so I used this [example](https://arrow-kt.io/docs/patterns/polymorphic_programs/) from the excellent Arrow documentation as a guide.

## Writing to the the console

In the previous article I used `IO<A>` to interact with the console. `IO<A>` represents an operation that can be executed lazily, fail with an exception (the exception is captured inside `IO`), run forever or return a single `A`. Let’s take a look at the original implementation:

```
fun putStrLn(line: String): IO<Unit> = IO { println(line) }

// Usage in main()
putStrLn("Hello world!").unsafeRunSync()
```

`putStrLn` is a function that take a `String` and return a `IO<Unit>`. `IO` takes a lambda that is lazily evaluated at the end of the world, when we call `unsafeRunSync()`. If we want to achieve the same thing with `Single` we could use `Single.fromCallable` wrap our lambda and evaluate it in the main function when we call `subscribe()`.

```
fun putStrLn(line: String): Single<Unit> = Single.fromCallable {
    println(line)
}

// Usage in main()
putStrLn("Hello World").subscribe()
```

Here both`IO` and `Single` have something in common. A set of **capabilities** like: **lazy evaluation** , **exception handling** , and **running forever** or **completing with a result** of type `A`. `IO` and `Single` do a lot more, but for this use case, we want something as simple as possible that has the same capabilities. There is a type-class in Arrow that can do just that and it’s called `MonadDefer`([more info](https://arrow-kt.io/docs/effects/monaddefer/)). After a few iterations, and feedback from the Arrow team, this is the code I came up with for printing to the console.

```
fun <F> putStrLn(M: MonadDefer<F>, line: String): Kind<F, Unit> = M.invoke {
    println(line)
}
```

The `putStrLn` function is generic with type `F`, but not any `F`. This `F`, whatever it is, need to do certain things like **lazy evaluation** and **error handling**. This `F` thing needs the **capabilities** of `MonadDefer`. The return value also needs a type parameter, and in Arrow we can do that by returning `Kind<F, SOMETHING>`. In the case of printing to command line, that `SOMETHING` is `Unit` (no return value). `MonadDefer` comes with an `invoke` function that we can use to construct the value of `Kind<F, Unit>`. We pass a lambda inside which will be lazily evaluated.

Compared to the original implementation we have a few key differences:

- a type parameter `F`
- one more parameter of type `MonadDefer<F>`
- the return type is `Kind<F, Unit>` instead of `IO<Unit>`

Now we can use this function to print something to the console. In order to do that, we need a data type that has the **capabilities** of `MonadDefer`. `IO` can do that so we can use it. Arrow also ships with `SingleK`, a wrapper for `Single` that has the `MonadDefer` capabilities.

```
putStrLn(IO.monadDefer(), "Hello World!").fix()
        .unsafeRunSync()

putStrLn(SingleK.monadDefer(), "Hello World!").fix()
        .single.subscribe()
```

Arrow also ships with `ObservableK` for `Observable`, `DeferredK` for coroutines etc.

## Reading from the console

Reading from the console is similar to writing to it. We still need a type parameter `F`, we still need to return `Kind<F, SOMETHING>` and we need to perform the operation lazily with success or an error. `readLine()` returns a nullable `String?` and if that happens we need to signal an error.

```
// Original code
fun getStrLn(): IO<String> = IO { readLine() ?: throw IOException("Failed to read input!") }

// Polymorphic code
fun <F> getStrLn(M: MonadDefer<F>): Kind<F, String> = M.invoke {
    readLine() ?: throw IOException("Failed to read input!")
}
```

## Reading from the console #2

I am throwing an `IOException` to indicate failure. `IO` would wrap that exception so it isn’t that bad. But there is a better way (thanks [Leandro](https://twitter.com/mLeandroBF)).

I convert the nullable `String?` to an `Option<String>`. Then I use `fold` to check if the `Option` has a value. If it’s empty I use `raiseError` to create `MonadDefer` which when evaluated returns an error. If it’s not empty I create a `MonadDefer` that returns a `String` using `just`.

The key difference here is I am NOT throwing the `IOException`. Using exceptions can be [expensive](http://java-performance.info/throwing-an-exception-in-java-is-very-slow/).

`M.defer` here means the `readLine()` happens lazily.

```
fun <F> getStrLn(M: MonadDefer<F>): Kind<F, String> = M.defer {
    readLine().toOption()
            .fold(
                    { M.raiseError<String>(IOException("Failed to read input!")) },
                    { M.just(it) }
            )
}
```

## The Hangman class

The next step is to make the `Hangman` class polymorphic. To do that I added a type parameter `F` and property of the type `MonadDefer<F>`.

```
class Hangman<F>(private val M: MonadDefer<F>) {
    ...
}
```

## Choosing a letter

To make the `getChoice()` function work in a polymorphic way we need a few changes. The return type changes from `IO<Char>` to `Kind<F, Char>`. `IO.binding` becomes `M.binding` (where `M` is the property of type `MonadDefer<F>`).

The `getStrLn()` and `putStrLn()` also need `M` as the parameter.

```
fun getChoice(): Kind<F, Char> = M.binding {
        putStrLn(M, "Please enter a letter").bind()
        val line = getStrLn(M).bind()
        val char = line.toLowerCase().first().toOption().fold(
                {
                        putStrLn(M, "Please enter a letter")
                                .flatMap { getChoice() }
                },
                { char ->
                        M { char }
                }
        ).bind()
        char
}
```

## Wrapping up

Updating all other functions follows the same pattern. Replace `IO<SOMETHING>` with `Kind<F, SOMETHING>`, replace `IO.binding` with `M.binding` and pass `M` as parameter for reading/writing to the console.

You can find the full code [here](https://gist.github.com/LordRaydenMK/0be8f70f860a862e69daf262b4a83e17).

## The main program

The main program, run with `Single`, looks like this:

```
Hangman(SingleK.monadDefer()).hangman.fix().single.subscribe()
```

or with `IO`

```
Hangman(IO.monadDefer()).hangman.fix().unsafeRunSync()
```

The decision in which type constructor to run is made at the point of execution. Switching from `Single` to `IO` or `Observable` requires only updating the main function.

## Incremental improvements

I am still learning FP and I don’t know most of the type-classes in Arrow and what they can do. In my first attempt I used `Async` instead of `MonadDefer`. `Async` extend `MonadDefer` and adds additional capabilities to it. I asked for feedback on the [#arrow](https://kotlinlang.slack.com/messages/C5UPMM0A0/) channel and they pointed me towards `MonadDefer`. Together with the Arrow maintainers we made a few more improvements improvements.

To avoid passing `M` to `printStrLn` every time I can convert it to an extension function on `MonadDefer`

```
fun <F> MonadDefer<F>.putStrLn(line: String): Kind<F, Unit> = invoke {
    println(line)
}
```

and I can use [Implementation by delegation](https://kotlinlang.org/docs/reference/delegation.html#implementation-by-delegation) and have the `Hangman` class implement `MonadDefer<F>`.

```
class Hangman<F>(private val M: MonadDefer<F>): MonadDefer<F> by M
```

This means everywhere inside the `Hangman` class I can use the methods of `MonadDefer` like `binding` and `invoke` and extension methods like `putStrLn`.

```
val hangman: Kind<F, Unit> = binding {
        putStrLn("Welcome to purely functional hangman").bind()
        val name = getName.bind()
        putStrLn("Welcome $name. Let's begin!").bind()
        val word = chooseWord.bind()
        val state = State(name, word = word)
        renderState(state).bind()
        gameLoop(state).bind()
        Unit
    }
```

You can find the full implementation [here](https://github.com/LordRaydenMK/arrow-hangman/blob/master/src/main/kotlin/io/github/lordraydenmk/part2/Part2.kt).

# Conclusion

Working with abstractions like `MonadDefer` frees the business logic from implementation details like `IO` or `Single`. It can also enable easier composition of different modules because the decision for the concrete data type is delayed until the main program.