Last active
February 13, 2020 14:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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