Skip to content

Instantly share code, notes, and snippets.

@ffgiraldez
Last active March 29, 2019 14:10
Show Gist options
  • Save ffgiraldez/c2fb37d2a6a7a24df9d90d40864be404 to your computer and use it in GitHub Desktop.
Save ffgiraldez/c2fb37d2a6a7a24df9d90d40864be404 to your computer and use it in GitHub Desktop.
FP to the Max on Arrow FX
package es.ffgiraldez.gist.arrow
import arrow.core.Option
import arrow.core.Try
import arrow.effects.extensions.io.fx.fx
import arrow.effects.extensions.io.unsafeRun.runBlocking
import arrow.unsafe
import java.util.Random
interface Console {
suspend fun putStrLn(s: String): Unit
suspend fun getStrLn(): String
}
object CommandLine : Console {
override suspend fun putStrLn(s: String) = println(s)
override suspend fun getStrLn(): String = readLine() ?: ""
}
interface Generator {
suspend fun nextInt(upper: Int): Int
}
object RandomGenerator : Generator {
private val random: Random = Random()
override suspend fun nextInt(upper: Int): Int = random.nextInt(upper) + 1
}
class FpToTheMax(
private val console: Console,
private val generator: Generator
) {
fun program() = fx {
!effect { console.putStrLn("What is your name?") }
val name = !effect { console.getStrLn() }
!effect { console.putStrLn("your name is $name") }
!effect { gameLoop(name) }
}
private fun parseInt(s: String): Option<Int> = Try { s.toInt() }.toOption()
private suspend fun gameLoop(name: String) {
val num = generator.nextInt(5)
console.putStrLn("Dear $name, please guess a number from 1 to 5:")
val input = console.getStrLn()
parseInt(input).fold(
{ console.putStrLn("You did not enter a number") },
{ guess ->
if (guess == num) console.putStrLn("You guessed right, $name!")
else console.putStrLn("You guessed wrong, $name! The number was: $num")
}
)
val cont = checkContinue(name)
return if (cont) gameLoop(name)
else Unit
}
private suspend fun checkContinue(name: String): Boolean {
console.putStrLn("Do you want to continue, $name?")
val input = console.getStrLn().toLowerCase()
return when (input) {
"y" -> true
"n" -> false
else -> checkContinue(name)
}
}
}
val FPInstance = FpToTheMax(CommandLine, RandomGenerator)
fun main(args: Array<String>) {
unsafe { runBlocking { FPInstance.program() } }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment