Functional Hangman in Kotlin with Arrow
Tags: kotlin, functional, arrowkt
Published: 2018-11-13 20:36:30

---
title: Functional Hangman in Kotlin with Arrow
published: true
tags: kotlin,functional,arrowkt
canonical_url: 
---

A few days ago I run into this [blog post](https://abhsrivastava.github.io/2018/11/03/Hangman-Game-Using-ZIO/) about implementing a console Hangman game using [Scala ZIO](https://scalaz.github.io/scalaz-zio/). The blog post is based on [this talk](https://www.youtube.com/watch?v=XONTFZ4afY0) delivered by [John De Goes](https://twitter.com/jdegoes), for the Scala Kyiv meetup, where he codes a console Hangman game using functional programming.

After I saw the post I was curious how the code would look like written in Koltin with [arrow](https://arrow-kt.io) so I decided to try and write it. You can find the result [here](https://github.com/LordRaydenMK/arrow-hangman).

I am still learning functional programming so I asked for [feedback](https://kotlinlang.slack.com/archives/C5UPMM0A0/p1541707359083600) from the arrow maintainers on the [kotlinlang](https://kotlinlang.slack.com/) slack workspace. They were very helpful and I made a few improvements based on their feedback.

# Key differences

I would like to point out that the programs in Scala and Kotlin are not 100% equivalent. There are both differences in the language and the functional libraries used.

## The IO monad

In Scala ZIO `IO[E, A]` describes an effect that may fail with an `E`, run forever, or produce a single `A`. In the Kotlin version I am using `IO<A>` from Arrow. `IO<A>` describes an effect that can fail with `Throwable` or produce a single `A`.

Both type classes produce an `A`. The key difference the error. In Scala ZIO you can use any error type or even `Nothing` to indicate the program never ends. In Arrow the `E` type is always `Throwable` so you don’t have to specify it.

## Reading and writing from the Console

Scala ZIO comes with built in primitives for interacting with the [console](https://scalaz.github.io/scalaz-zio/usage/console.html). In the Kotlin version I had to implement the `readStrLn` and `putStrLn` functions myself.

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

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

```

## For comprehensions

[For comprehensions](https://docs.scala-lang.org/tour/for-comprehensions.html) are built into the scala language. Unfortunately Kotlin doesn’t have the same feature. But Kotlin has [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) so the Arrow team built [Comprehensions over coroutines](https://arrow-kt.io/docs/patterns/monad_comprehensions/#comprehensions-over-coroutines) which can be used in a similar way to make the code more readable.

```
//Scala with For comprehensions
val hangman : IO[IOException, Unit] = for {
    _ <- putStrLn("Welcome to purely functional hangman")
    name <- getName
    _ <- putStrLn(s"Welcome $name. Let's begin!")
    word <- chooseWord
    state = State(name, Set(), word)
    _ <- renderState(state)
    _ <- gameLoop(state)
} yield()
```


```
//Kotlin with Arrow (Comprehensions over coroutines)
val hangman: IO<Unit> = IO.monad().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
}.fix()

```

# Conclusion

Rewriting Functional Hangman from Scala to Kotlin was a nice exercise for learning FP. There are differences between Scala and Kotlin and the `IO` type class in Scala ZIO and Arrow but the core principles are the same, we write programs by solving small problems and then combine the solutions. We use lazy evaluation and move the side effects to the edge of the system.

Thanks to John who wrote this functional hangman, [Abhishek](https://twitter.com/abhishes) for writing the article and [Paco](https://twitter.com/pacoworks), [Raul](https://twitter.com/raulraja) and [Leandro](https://twitter.com/mLeandroBF), from the Arrow team, for the feedback about my code.