Skip to content

Instantly share code, notes, and snippets.

@gustavofranke
Last active February 13, 2020 14:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gustavofranke/287103e55b456953a34776f97f3b93d0 to your computer and use it in GitHub Desktop.
Save gustavofranke/287103e55b456953a34776f97f3b93d0 to your computer and use it in GitHub Desktop.
John de Goes' Fpmax in a granular way that helps me to visualise the sequence refactoring steps, I stopped when the code became testable
package fpmax
import scala.io.StdIn.readLine
import scala.util.Try
object App0 extends App {
def main(): Unit = {
println("What is your name?")
val name = readLine()
println("Hello, " + name + ", welcome to the game!")
var exec = true
while (exec) {
val num = scala.util.Random.nextInt(5) + 1
println("Dear " + name + ", please guess a number from 1 to 5:")
val guess = readLine().toInt
if (guess == num) println("You guessed right, " + name + "!")
else println("You guessed wrong, " + name + "! The number was: " + num)
println("Do you want to continue, " + name + "?")
readLine() match {
case "y" => exec = true
case "n" => exec = false
}
}
}
main()
}
object App1 extends App {
def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
def main(): Unit = {
println("What is your name?")
val name = readLine()
println("Hello, " + name + ", welcome to the game!")
var exec = true
while (exec) {
val num = scala.util.Random.nextInt(5) + 1
println("Dear " + name + ", please guess a number from 1 to 5:")
parseInt(readLine()).fold(println("should be an int"))(guess =>
if (guess == num) println("You guessed right, " + name + "!")
else println("You guessed wrong, " + name + "! The number was: " + num)
)
var cont = true
while(cont) {
cont = false
println("Do you want to continue, " + name + "?")
readLine() match {
case "y" => exec = true
case "n" => exec = false
case _ => cont = true
}
}
}
}
main()
}
object App2 extends App {
def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
def checkContinue(name: String): Unit = {
println("Do you want to continue, " + name + "?")
readLine() match {
case "y" => gameLoop(name)
case "n" => sys.exit()
case _ => checkContinue(name)
}
}
def gameLoop(name: String): Unit = {
val num = scala.util.Random.nextInt(5) + 1
println("Dear " + name + ", please guess a number from 1 to 5:")
parseInt(readLine()).fold(println("should be an int"))(guess =>
if (guess == num) println("You guessed right, " + name + "!")
else println("You guessed wrong, " + name + "! The number was: " + num)
)
checkContinue(name)
}
def main(): Unit = {
println("What is your name?")
val name = readLine()
println("Hello, " + name + ", welcome to the game!")
gameLoop(name)
}
main()
}
object App3 extends App {
def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
def checkContinue(name: String): Boolean = {
println("Do you want to continue, " + name + "?")
readLine() match {
case "y" => true
case "n" => false
case _ => checkContinue(name)
}
}
def gameLoop(name: String): Unit = {
val num = scala.util.Random.nextInt(5) + 1
println("Dear " + name + ", please guess a number from 1 to 5:")
parseInt(readLine()).fold(println("should be an int"))(guess =>
if (guess == num) println("You guessed right, " + name + "!")
else println("You guessed wrong, " + name + "! The number was: " + num)
)
if (checkContinue(name)) gameLoop(name) else sys.exit()
}
def main(): Unit = {
println("What is your name?")
val name = readLine()
println("Hello, " + name + ", welcome to the game!")
gameLoop(name)
}
main()
}
case class IO[A](unsafeRun: () => A) { self =>
def map[B](f: A => B): IO[B] = IO(() =>f(self.unsafeRun()))
def flatMap[B](f: A => IO[B]): IO[B] = IO(() => f(self.unsafeRun()).unsafeRun())
}
object IO {
def pure[A](a: A): IO[A] = IO(() => a)
////
implicit val ProgramIO: Program[IO] = new Program[IO] {
override def pure[A](a: A): IO[A] = IO.pure(a)
override def map[A, B](fa: IO[A], f: A => B): IO[B] = fa.map(f)
override def flatMap[A, B](fa: IO[A], f: A => IO[B]): IO[B] = fa.flatMap(f)
}
implicit val ConsoleIO: Console[IO] = new Console[IO] {
override def putStrLn(line: String): IO[Unit] = IO(() => println(line))
override def getStrLn: IO[String] = IO(() => readLine())
}
implicit val RandomIO: Random[IO] = new Random[IO] {
override def nextInt(upper: Int): IO[Int] = IO(() => scala.util.Random.nextInt(upper))
}
}
object App4 extends App {
def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
def putStrLn(line: String): IO[Unit] = IO(() => println(line))
def getStrLn: IO[String] = IO(() => readLine())
def nextInt(upper: Int): IO[Int] = IO(() => scala.util.Random.nextInt(upper))
def checkContinue(name: String): IO[Boolean] = for {
_ <- putStrLn("Do you want to continue, " + name + "?")
in <- getStrLn
cont <- in match {
case "y" => IO.pure(true)
case "n" => IO.pure(false)
case _ => checkContinue(name)
}
} yield cont
def gameLoop(name: String): IO[Unit] = for {
num <- nextInt(5).map(_ + 1)
_ <- putStrLn("Dear " + name + ", please guess a number from 1 to 5:")
in <- getStrLn
_ <- parseInt(in).fold(putStrLn("should be an int"))(guess =>
if (guess == num) putStrLn("You guessed right, " + name + "!")
else putStrLn("You guessed wrong, " + name + "! The number was: " + num)
)
cont <- checkContinue(name)
_ <- if (cont) gameLoop(name) else sys.exit()
} yield ()
def main(): IO[Unit] = for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn("Hello, " + name + ", welcome to the game!")
_ <- gameLoop(name)
} yield ()
main().unsafeRun()
}
import scala.language.higherKinds
trait Program[F[_]] {
def pure[A](a: A): F[A]
def map[A, B](fa: F[A], f: A => B): F[B]
def flatMap[A, B](fa: F[A], f: A => F[B]): F[B]
}
object Program {
def apply[F[_]](implicit F: Program[F]): Program[F] = F
implicit class ProgramSyntax[F[_], A](fa: F[A]) {
def map[B](f: A => B)(implicit F: Program[F]): F[B] = F.map(fa, f)
def flatMap[B](f: A => F[B])(implicit F: Program[F]): F[B] = F.flatMap(fa, f)
}
}
trait Console[F[_]] {
def putStrLn(line: String): F[Unit]
def getStrLn: F[String]
}
object Console {
def apply[F[_]](implicit F: Console[F]): Console[F] = F
}
trait Random[F[_]] {
def nextInt(upper: Int): F[Int]
}
object Random {
def apply[F[_]](implicit F: Random[F]): Random[F] = F
}
object App5 extends App {
import Program._
def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
def finish[F[_], A](a: A)(implicit F: Program[F]): F[A] = F.pure(a)
def putStrLn[F[_]](line: String)(implicit F: Console[F]): F[Unit] = F.putStrLn(line)
def getStrLn[F[_]](implicit F: Console[F]): F[String] = F.getStrLn
def nextInt[F[_]](upper: Int)(implicit F: Random[F]): F[Int] = F.nextInt(upper)
def checkContinue[F[_]: Program: Console: Random](name: String): F[Boolean] = for {
_ <- putStrLn("Do you want to continue, " + name + "?")
in <- getStrLn
cont <- in match {
case "y" => finish(true)
case "n" => finish(false)
case _ => checkContinue(name)
}
} yield cont
def gameLoop[F[_]: Program: Console: Random](name: String): F[Unit] = for {
num <- nextInt(5).map(_ + 1)
_ <- putStrLn("Dear " + name + ", please guess a number from 1 to 5:")
in <- getStrLn
_ <- parseInt(in).fold(putStrLn("should be an int"))(guess =>
if (guess == num) putStrLn("You guessed right, " + name + "!")
else putStrLn("You guessed wrong, " + name + "! The number was: " + num)
)
cont <- checkContinue(name)
_ <- if (cont) gameLoop(name) else finish(())
} yield ()
def main[F[_]: Program: Console: Random](): F[Unit] = for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn("Hello, " + name + ", welcome to the game!")
_ <- gameLoop(name)
} yield ()
def mainIO: IO[Unit] = main[IO]()
mainIO.unsafeRun()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment