Last active
October 23, 2021 10:49
-
-
Save fancellu/fcfccc5195e4d70a215b7ced6cab570b to your computer and use it in GitHub Desktop.
Simple example of an IO effect Monad, no Cats, no ZIO
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
import scala.util.Random | |
// Simple example of an IO effect Monad, no Cats | |
object MyIO extends App{ | |
// IO encapsulates a side effecting operation | |
final class IO[A](val run: () => A) { | |
def map[B](f: A => B): IO[B] = IO(f(run())) | |
def flatMap[B](f: A => IO[B]): IO[B] = IO(f(run()).run()) | |
} | |
object IO { | |
def apply[A](a: =>A): IO[A] = new IO(() => a) | |
} | |
// Some example type classes, without regard to context | |
trait Console[C[_]] { | |
def read: C[String] | |
def readBoolean: C[Boolean] | |
def write(st: String): C[Unit] | |
} | |
trait Random[C[_]] { | |
def randomString: C[String] | |
} | |
// we implement IOs for above type classes, which is where we perform our side effects | |
object ConsoleIO extends Console[IO] { | |
def read: IO[String] = IO { io.StdIn.readLine } | |
def readBoolean: IO[Boolean] = IO { io.StdIn.readBoolean } | |
def write(st: String): IO[Unit] = IO { println(st) } | |
} | |
object RandomIO extends Random[IO] { | |
def randomString: IO[String]= IO {Random.alphanumeric.take(8).mkString} | |
} | |
// composing an IO with for comprehensions | |
def prog(consoleIO: Console[IO], randomIO: Random[IO]): IO[String] ={ | |
import consoleIO._ | |
import randomIO._ | |
println("running"*10) | |
for { | |
_<- write("please enter a word") | |
readWord <- read.map(_+" !!!") | |
_<- write("do you like cats?") | |
boolean <- readBoolean | |
randomString1 <- randomString | |
randomString2 <- randomString | |
str=s"$readWord,$boolean,$randomString1,$randomString2" | |
_<- write(str) | |
} yield str | |
} | |
println("Nothing is run yet, running now") | |
val out=prog(ConsoleIO,RandomIO).run() | |
println(s"out=$out") | |
object FakeConsoleIO extends Console[IO] { | |
def read: IO[String] = IO { "fake" } | |
def readBoolean: IO[Boolean] = IO { true } | |
def write(st: String): IO[Unit] = IO { () } | |
} | |
object FakeRandomIO extends Random[IO] { | |
def randomString: IO[String]= IO {"fakefake"} | |
} | |
// here we run again but with canned IOs, nothing comes from real console or real random source | |
val out2=prog(FakeConsoleIO,FakeRandomIO).run() | |
println(s"out2=$out2") | |
// we create 2 random numbers here, and output them | |
val rnd: IO[Unit] =for { | |
randomString1 <- RandomIO.randomString | |
randomString2 <- RandomIO.randomString | |
str=s"$randomString1,$randomString2" | |
_<- ConsoleIO.write(str) | |
} yield () | |
// note, both runs create different numbers, nothing is memoized | |
rnd.run() | |
rnd.run() | |
} |
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
Nothing is run yet, running now | |
runningrunningrunningrunningrunningrunningrunningrunningrunningrunning | |
please enter a word | |
woof | |
do you like cats? | |
n | |
woof !!!,false,MisEM4ds,qkdC6hIR | |
out=woof !!!,false,MisEM4ds,qkdC6hIR | |
runningrunningrunningrunningrunningrunningrunningrunningrunningrunning | |
out2=fake !!!,true,fakefake,fakefake | |
qOA3J11v,pNhxfc2o | |
igrcGfC9,YizkSMkv |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment