Once upon a time there was some stinky side affecting code with println all over the place.
How horrible! No, Cinderella, you definitely can't meet the prince of MonadLand looking like that!
Fortunately her Functional Fairy Godmother is on hand.

'Ah ha' she cries! From each function you need to return both the int (which is the existing return type) and some Strings to represent the logs!
'Easy peasy' she says and with a swish of her magic wand she transforms Cinderella.
Well I guess this is ok, but look how much more effort Cinderella has to go to to compose f and g! That's not very elegant at all!
'Please, Fairy Godmother', Cinderella begs, 'Isn't there anything more you can do?'
Now it's a little-known Disney secret that Cinderella's Functional Fairy Godmother is actually an enormous fan of Cats and has a clever Writer monad trick up her sleeve.
Output:
WriterT((Vector(Generating random int, Applying complex mathematical formula),84))
WriterT((Vector(Generating random int, Applying complex mathematical formula),84))
'Oh thank you Functional Fairy Godmother', cries Cinderella, delighted.
FFG winks and whispers, 'I just love a good for comprehension! There are actually a lot of different ways of creating a writer!', and she slips some example code into Cinderella's pocket for later bedtime reading, in case things with the prince don't go to plan:
Cinderella was so intrigued by these examples that she stayed up all night reading Dave Gurnell and Noel Walsh's book Scala with Cats and skipped the ball entirely.

And she lived happily ever after.
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
object Cinderella1 extends App { | |
def f(): Int = { | |
println("Generating random int") | |
42 | |
} | |
def g(i: Int): Int = { | |
println("Applying complex mathematical formula") | |
i * 2 | |
} | |
g(f()) | |
} |
Fortunately her Functional Fairy Godmother is on hand.

'Ah ha' she cries! From each function you need to return both the int (which is the existing return type) and some Strings to represent the logs!
'Easy peasy' she says and with a swish of her magic wand she transforms Cinderella.
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
object Cinderella2 extends App { | |
def f: (Int, Vector[String]) = { | |
(42, Vector("Generating random int")) | |
} | |
def g(i: Int): (Int, Vector[String]) = { | |
(i % 2, Vector("Applying complex mathematical formula")) | |
} | |
val (i, vs1) = f | |
val (result, vs2) = g(i) | |
val printStatements = vs1 ++ vs2 | |
println(printStatements) | |
println(result) | |
} |
'Please, Fairy Godmother', Cinderella begs, 'Isn't there anything more you can do?'
Now it's a little-known Disney secret that Cinderella's Functional Fairy Godmother is actually an enormous fan of Cats and has a clever Writer monad trick up her sleeve.
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
object Cinderella3 extends App { | |
import cats.data.Writer | |
import cats.instances.vector._ | |
import cats.syntax.applicative._ | |
import cats.syntax.writer._ | |
type Logged[A] = Writer[Vector[String], A] | |
def f: Logged[Int] = for { | |
n <- 42.pure[Logged] | |
_ <- Vector("Generating random int").tell | |
} yield n | |
def g(i: Int): Logged[Int] = for { | |
n <- i.pure[Logged] | |
_ <- Vector("Applying complex mathematical formula").tell | |
} yield n * 2 | |
private val result1 = for { | |
i <- f | |
result <- g(i) | |
} yield result | |
private val result2 = f.flatMap(g) | |
println(result1) | |
println(result2) | |
} |
WriterT((Vector(Generating random int, Applying complex mathematical formula),84))
WriterT((Vector(Generating random int, Applying complex mathematical formula),84))
'Oh thank you Functional Fairy Godmother', cries Cinderella, delighted.
FFG winks and whispers, 'I just love a good for comprehension! There are actually a lot of different ways of creating a writer!', and she slips some example code into Cinderella's pocket for later bedtime reading, in case things with the prince don't go to plan:
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
object DifferentWaysOfCreatingACatsWriter extends App { | |
import cats.data.Writer | |
import cats.instances.vector._ | |
import cats.syntax.applicative._ | |
import cats.syntax.writer._ | |
type Logged[A] = Writer[Vector[String], A] | |
def f1: Logged[Int] = { | |
val magicNumber = 42 | |
magicNumber.writer(Vector("Generating random int")) | |
} | |
def f2: Logged[Int] = for { | |
n <- 42.pure[Logged] | |
_ <- Vector("Generating random int").tell | |
} yield n | |
def f3: Logged[Int] = { | |
val magicNumber = (42 | |
Writer(Vector("Generating random int"), magicNumber) | |
} | |
println(f1) | |
println(f2) | |
println(f3) | |
} |

And she lived happily ever after.
No comments:
Post a Comment