Tout ce qui n'est pas retourné
def impureParse(str: String): Int = str.toInt
impureParse("test") //throw java.lang.NumberFormatException
var i = 1;
def add(j: Int): Int = {
i += j
i
}
add(2) // 3
i // also 3
scala.io.Source.fromFile("/a_file.txt").getLines
println("Hello")
Random.nextInt()
def doSomething(): Unit = ()
def impureAdd(i: Int, j:Int): Int = {
println("Hello")
i + j
}
case class Can()
case class Coin()
def sell(money: Coin): Can = ???
val can1 = sell(Coin())
val can2 = sell(Coin())
val can3 = sell(Coin())
val cans = List(can1, can2, can3)
println("cans", cans)
object ApiLowLevel {
// true if OK, false if it can't deliver
def giveACan(): Boolean = ???
}
var stock = 10
def sell(money: Coin): Can = {
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
stock = stock - 1
Can()
}
}
}
var stock = 10
def sell(money: Coin): Can = {
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
stock = stock - 1
Can()
} else {
throw new Exception("Can stuck")
}
} else {
throw new Exception("No more stock")
}
}
val cans = mutable.MutableList[Can]()
val errors = mutable.MutableList[Throwable]()
try {cans += sell(Coin())} catch {case e => errors += e}
try {cans += sell(Coin())} catch {case e => errors += e}
try {cans += sell(Coin())} catch {case e => errors += e}
println("cans", cans)
println("errors", errors)
var stock = 10
def sell(money: Coin): Option[Can] = {
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
stock = stock - 1
Some(Can())
} else {
None
}
} else {
None
}
}
Try
?
sealed trait MachineError
object MachineError {
case object CanStuck extends MachineError
case object EmptyStock extends MachineError
}
var stock = 10
def sell(money: Coin): Either[MachineError, Can] = {
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
stock = stock - 1
Right(Can())
} else {
Left(CanStuck)
}
} else {
Left(EmptyStock)
}
}
val maybeCans: Seq[Either[MachineError, Can]] = List(
sell(Coin()),
sell(Coin()),
sell(Coin())
)
val cans: Seq[Can] = maybeCans.collect {
case Right(can) => can
}
val errors: Seq[MachineError] = maybeCans.collect {
case Left(e) => e
}
println("cans", cans)
println("errors", errors)
type CanOrErr = Either[MachineError, Can]
def sell(money: Coin)(stock: Int): (Int, CanOrErr) = {
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
(stock - 1, Right(Can()))
} else {
(stock, Left(CanStuck))
}
} else {
(stock, Left(EmptyStock))
}
}
val (stock1, maybeCan1) = sell(Coin())(10)
val (stock2, maybeCan2) = sell(Coin())(stock1)
val (stock3, maybeCan3) = sell(Coin())(stock2)
val maybeCans = List(maybeCan1, maybeCan2, maybeCan3)
val cans = maybeCans.collect {
case Right(snack) => snack
}
val errors = maybeCans.collect {
case Left(e) => e
}
println("cans", cans)
println("errors", errors)
println("stock", stock3)
type State[S, T] ~ (S) => (S, T)
import cats.data.State
def sell(coin: Coin): State[Int, CanOrErr] = State { stock =>
if (stock > 0) {
if (ApiLowLevel.giveACan()) {
(stock - 1, Right(Can()))
} else {
(stock, Left(CanStuck))
}
} else {
(stock, Left(EmptyStock))
}
}
val state: State[Int, List[CanOrErr]] = for {
maybeCan1 <- sell(Coin())
maybeCan2 <- sell(Coin())
maybeCan3 <- sell(Coin())
} yield List(maybeCan1, maybeCan2, maybeCan3)
val (stock, maybeCans) = state.run(10).value
val cans = maybeCans.collect { case Right(can) => can }
val errors = maybeCans.collect { case Left(e) => e }
println("cans", cans)
println("errors", errors)
println("stock", stock)
type IO[A] ~ (RealWorld) => (RealWorld, A)
def purePrint(str: String): IO[Unit] = IO(println(str))
def pureRnd(): IO[Int] = IO(Random.nextInt())
val sum: IO[Int] = for {
n1 <- pureRnd()
_ <- purePrint(n1.toString)
n2 <- pureRnd()
} yield r1 + r2
sum.unsafeRunSync()
IO
est un marqueur optionnelOption
: arrêt prématuréEither
: arrêt prématuré avec une raisonFuture
: asynchronismecats.data.Writer
: : écrire quelque partcats.data.Reader
: lire de quelque partcats.data.State
: modifier un état interne
object Pocket {
def getCoin(): Option[Coin] = ???
}
object Api {
def getACan(coin: Coin): Future[Option[Can]] = ???
}
object Trash {
def recycle(can: Can): Future[Option[Coin]] = ???
}
val eventualMaybeCoin: Future[Option[Coin]] = {
Pocket.getCoin() match {
case Some(coin) => Api.getACan(coin).flatMap {
case Some(can) => Trash.recycle(can)
case None => Future(None)
}
case None => Future(None)
}
}
type OptionT[M[_], A] ~ M[Option[A]]
import cats.data.OptionT
val eventualMaybeCoin: OptionT[Future, Coin] = for {
coin <- OptionT.fromOption[Future](Pocket.getCoin())
can <- OptionT(Api.getACan(coin))
newCoin <- OptionT(Trash.recycle(can))
} yield {
newCoin
}
val r: Future[Option[Coin]] = eventualMaybeCoin.value
def double(p: Future[Option[Int]]): Future[Option[Int]] = {
p.map(maybeI => maybeI.map(i => i * 2))
}
def double(p: Future[Option[Int]]): Future[Option[Int]] = {
p.map(_.map(_ * 2))
}
def double(p: Future[Option[Int]]): Future[Option[Int]] = {
OptionT(p).map(_ * 2).value
}
type FutureOpt[A] = Future[Option[A]]
def add(p1:FutureOpt[Int], p2:FutureOpt[Int]):FutureOpt[Int] =
p1.flatMap { maybeI1 =>
p2.map { maybeI2 =>
maybeI1.flatMap(i1 => maybeI2.map(i2 => i1 + i2))
}
}
type FutureOpt[A] = Future[Option[A]]
def add(p1:FutureOpt[Int], p2:FutureOpt[Int]):FutureOpt[Int] =
for {
maybeI1 <- p1
maybeI2 <- p2
} yield for {
i1 <- maybeI1
i2 <- maybeI2
} yield i1 + i2
def add(p1:FutureOpt[Int], p2:FutureOpt[Int]):FutureOpt[Int] = {
(for {
i1 <- OptionT(p1)
i2 <- OptionT(p2)
} yield i1 + i2).value
}
type OptionF[A] = OptionT[Future, A]
val maybeCoin = OptionT.fromOption[Future](Pocket.getCoin())
val recipe: WriterT[OptionF, String, Coin] = for {
coin <- WriterT.lift[OptionF, String, Coin](maybeCoin)
_ <- WriterT.tell[OptionF, String](s"got $coin;")
snack <- WriterT.lift(OptionT(Api.getACan(coin)))
_ <- WriterT.tell[OptionF, String](s"got $snack;")
newCoin <- WriterT.lift(OptionT(Trash.recycle(snack)))
_ <- WriterT.tell[OptionF, String](s"recycled $snack;")
} yield newCoin
val r: Future[Option[(String, Coin)]] = recipe.run.value
for
type EitherStr[A] = Either[String, A]
type _eitherStr[R] = EitherStr |= R
def add[R : _option : _eitherStr](
maybeInt: Option[Int],
intOrStr: Either[String, Int]): Eff[R, Int] = for {
a <- fromOption(maybeInt)
b <- fromEither(intOrStr)
} yield a + b
type Stack = Fx.fx2[Option, EitherStr]
add[Stack](Some(1), Right(2)).runOption.runEither.run
//Right(Some(3))
add[Stack](Some(1), Left("err")).runOption.runEither.run
//Left("err")
type WriterStr[A] = Writer[String, A]
type _writerStr[R] = WriterStr |= R
type Stack = Fx.fx3[WriterStr, Option, TimedFuture]
def recipe[R : _writerStr : _option : _future]: Eff[R, Coin] =
for {
coin <- fromOption(Pocket.getCoin())
_ <- tell("got Coin " + coin)
maybeCan <- fromFuture(Api.getACan(coin))
can <- fromOption(maybeCan)
_ <- tell("got Can " + can)
maybeNewCoin <- fromFuture(Trash.recycle(can))
newCoin <- fromOption(maybeNewCoin)
_ <- tell("recycled Can " + can)
} yield newCoin
val result: Future[Option[(Coin, List[String])]] =
recipe[Stack].runWriter.runOption.runAsync