## Cartesian Product in Scala Cats

During work, I have some problem handling three future at the same time. First future return a long value and second and third future receive the parameter from the first return and return a tuple.

The code is like this.

```
for {
long <- futureLong()
int <- futureInt(long)
char <- futureChar(long)
} yield (int, char)

```

Of course for comprehension operates step by step, so, futureInt is called after futureLong is finished and futureChar is called after futureInt is finished. So, It takes too much time to get a final return value.

So, I changed codes like this.

```
val longVal: Future[Long] = futureLong()

val intVal: Future[Int] = for {
long <- futureLong()
int <- futureInt(long)
} yield int

val charVal: Future[Char] = for {
long <- futureLong()
char <- futureChar(long)
} yield char

val forComp: (Int, Char) = Await.result(for {
int <- intVal
char <- charVal
} yield (int, char), 5 second)

```

Yes, It works as I want. But, there is duplicated codes like, ‘long <- futureLong()’. During thinking a long time, my coworker, Liam, recommends using  Cartesian Product.

### What is Cartesian Product?

Cartesian Product is very simple. It’s just a product of two Sets. For example, if there are two sets A = {1,2,3} and B = {‘a’, ‘b’, ‘c’}, Cartesian Product of A X B is

{(1, ‘a’), (1, ‘b’), (1, ‘c’), (2, ‘a’), (2, ‘b’), (2, ‘c’), (3, ‘a’), (3, ‘b’), (3, ‘c’)}

Yes. that’s all. Of course Cartesian Product didn’t hold commutative law. For example Cartesian Product of B X A is

{(‘a’, 1), (‘a’, 2), (‘a’, 3), (‘b’, 1), (‘b’, 2), (‘b’, 3), (‘c’, 1), (‘c’, 2), (‘c’, 3)}

And different from A X B.

### Cartesian Product in cats

Above example can be implemented in Scala.

```
import cats.instances.list._
import cats.syntax.all._

val ints: List[Int] = List(1, 2, 3, 4)
val chars: List[Char] = List('a', 'b', 'c')

(ints |@| chars).tupled
// res0: List[(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c), (4,a), (4,b), (4,c))
(chars |@| ints).tupled
// res1: List[(Char, Int)] = List((a,1), (a,2), (a,3), (a,4), (b,1), (b,2), (b,3), (b,4), (c,1), (c,2), (c,3), (c,4))

(ints |@| chars).map(_ + _.toString)
// res2: List[String] = List(1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c, 4a, 4b, 4c)
```

In Cats Cartesian Product Syntax is ‘|@|’.(Some people call it Oink, and others call Pizza box) If you call tuple, it will return List Tuple. You can also map it.

### Cartesian Product in Future

Ok, let’s return to the previous problem. I need to call futureInt and futureChar at a same time. And using three for comprehension is too dirty. So, how and I solve this with Cartesian Product? It’s very simple.

```
for {
long <- futureLong()
(int, char) <- (futureInt(long) |@| futureChar(long)).tupled
} yield (int, char)

```

Very simple right? You can test whether this expression really operates at the same time.

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 org.example.ktz.blog import cats.syntax.all._ import cats.instances.future._ import org.scalatest._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scala.concurrent.{Await, Future} class CartesianProductTest extends FlatSpec with Matchers { def futureLong(): Future[Long] = Future { Thread.sleep(2000) println("Future Long Done!") 2 } def futureInt(long: Long): Future[Int] = Future{ Thread.sleep(2000) println("Future Int Done!") long.toInt } def futureChar(long: Long): Future[Char] = Future{ Thread.sleep(2000) println("Future Char Done!") long.toChar } "Concurrent" should "for comprehension" in { val forComp: (Int, Char) = Await.result(for { long <- futureLong() int <- futureInt(long) char <- futureChar(long) } yield (int, char), 5 second) // java.util.concurrent.TimeoutException: Futures timed out after [5 seconds] } "Concurrent" should "for comprehension2" in { val longVal: Future[Long] = futureLong() val intVal: Future[Int] = for { long <- futureLong() int <- futureInt(long) } yield int val charVal: Future[Char] = for { long <- futureLong() char <- futureChar(long) } yield char val forComp: (Int, Char) = Await.result(for { int <- intVal char <- charVal } yield (int, char), 5 second) // Work well 🙂 } "Concurrent" should "cartesian" in { val cartesion: (Int, Char) = Await.result(for { long <- futureLong() (int, char) <- (futureInt(long) |@| futureChar(long)).tupled } yield (int, char), 5 second) // Work well 🙂 } }

In this test, the first test occurs TimeoutException and second and third pass test well. Then, we can make a conclusion that, last expression also run at the same time.

Writer Monad is stack something while operating.

Hm… I think it’s not a very well summarized sentence. If any reader has nicer summarized one, comment me. Below example is from mastering advanced Scala.

### Example

type Writer id defined in cats like this.

```type Writer[L, V] = WriterT[Id, L, V]
```

As you can see, Writer Monad accept type L & V. type L is a type which stacks something. and V is a result(return) value. Id position in WirterT is something wraps the result. Here is Id so, never mind.

You can simply use Writer Monad like.

```import cats.data.Writer

def greetW(name: String, logged: Boolean): Writer[List[String], String] =
Writer(List("Compose a greeting"), {
val userName = if(logged) name else "User"
})

def isLoggedW(name: String): Writer[List[String], Boolean] =
Writer(List("Checking if user is logged in"), name.length == 3)

import cats.instances.list._

val name = "Joe"

val resultW: Writer[List[String], String] = for {
logged <- isLoggedW(name)
greeting <- greetW(name, logged)
} yield greeting
val (log, result) = resultW.run

// log: List[String] = List(Checking if user is logged in, Compose a greeting)
//result: String = Hello Joe
```

Yes. It’s very simple. It just stacks some strings in L(List[String]) and returns value in V(String). I think it’s very useful.

### How is it works?

Of course, you can have curious that how’s is it works? As you can see in ‘for comprehension’, there is nowhere to pass List[String]. But after finishing for comprehension, it splits out log: List[String] and result: String.

Let’s remind this.

For comprehension is syntactic sugar of flatMap.

You can also write like this.

```val flatMapResult: Writer[List[String], String] =
isLoggedW(name).flatMap(logged => greetW(name, logged))
```

It’s the same result of for comprehension statements.

Ok. It’s flatMap. Then, Let’s deep dive to WriterT.flatMap

```final case class WriterT[F[_], L, V](run: F[(L, V)]) {
...
def flatMap[U](f: V => WriterT[F, L, U])(implicit flatMapF: FlatMap[F], semigroupL: Semigroup[L]): WriterT[F, L, U] =
WriterT {
flatMapF.flatMap(run) { lv =>
flatMapF.map(f(lv._2).run) { lv2 =>
(semigroupL.combine(lv._1, lv2._1), lv2._2)
}
}
}
...
}
```

In this code, never mind another but line:7. In Line 7, they combine two List[String]. Stacking is occurred in here. WriterT is different from others. value run’s type is F[(L, V)] and it does flatMap with it. So we can stack List[String]

WriterT Example

WriterT is Monad Transformer of Writer. So, you can use like this.

```import cats.data.WriterT
import cats.instances.future._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def greetWFuture(name: String, logged: Boolean): WriterT[Future, List[String], String] =
WriterT(Future(List("Compose a greeting"), {
val userName = if(logged) name else "User"
}))

def isLoggedWFuture(name: String): WriterT[Future, List[String], Boolean] =
WriterT(Future(List("Checking if user is logged in"), name.length == 3))

val resultWFuture: WriterT[Future, List[String], String] = for {
logged <- isLoggedWFuture(name)
greeting <- greetWFuture(name, logged)
} yield greeting

val futureResult: Future[(List[String], String)] = resultWFuture.run

import scala.concurrent.Await
import scala.concurrent.duration._

val (logAwait, resultAwait) = Await.result(futureResult, 2 second)
```

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 cats.data.Writer def greetW(name: String, logged: Boolean): Writer[List[String], String] = Writer(List("Compose a greeting"), { val userName = if(logged) name else "User" s"Hello \$userName" }) def isLoggedW(name: String): Writer[List[String], Boolean] = Writer(List("Checking if user is logged in"), name.length == 3) import cats.instances.list._ val name = "Joe" val resultW: Writer[List[String], String] = for { logged <- isLoggedW(name) greeting <- greetW(name, logged) } yield greeting val (log, result) = resultW.run val flatMapResult: Writer[List[String], String] = isLoggedW(name).flatMap(logged => greetW(name, logged)) import cats.data.WriterT import cats.instances.future._ import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global def greetWFuture(name: String, logged: Boolean): WriterT[Future, List[String], String] = WriterT(Future(List("Compose a greeting"), { val userName = if(logged) name else "User" s"Hello \$userName" })) def isLoggedWFuture(name: String): WriterT[Future, List[String], Boolean] = WriterT(Future(List("Checking if user is logged in"), name.length == 3)) val resultWFuture: WriterT[Future, List[String], String] = for { logged <- isLoggedWFuture(name) greeting <- greetWFuture(name, logged) } yield greeting val futureResult: Future[(List[String], String)] = resultWFuture.run import scala.concurrent.Await import scala.concurrent.duration._ val (logAwait, resultAwait) = Await.result(futureResult, 2 second)

Below example is from mastering advanced Scala

At first, I thought Reader Monad is used to read something. It’s true. But another definition is effective.

Yes. I think it’s a better definition. Reader Monad object is like this.

```object Reader {
def apply[A, B](f: A => B): Reader[A, B] = ReaderT[Id, A, B](f)
}
```

Anonymous function f is the function we want to run. And ‘A’ will be injected later when we call like this.

```

```

ATypeInstance is an instance which type is A. And as you can see, is passed when you call run function.

### Example

First, Let’s suppose some Service like this.

```trait AuthService {
def isLogged(name: String): Boolean
}

class AuthServiceChar3 extends AuthService{
override def isLogged(name: String): Boolean = name.length == 3
}

class AuthServiceChar5 extends AuthService{
override def isLogged(name: String): Boolean = name.length == 5
}

trait UserService {
def greet(name: String, isLogged: Boolean): String
}

class UserServiceDefaultUser extends UserService{
override def greet(name: String, isLogged: Boolean): String = {
val actualName = if(isLogged) name else "User"

s"Hello \$actualName"
}
}

class UserServiceNoDefault extends UserService{
override def greet(name: String, isLogged: Boolean): String = {
if(isLogged) s"Hello \$name" else "No authorization"
}
}

case class Environment(userName: String, userService: UserService, authService: AuthService)
```

AuthService has a simple auth logic and actualized class is AuthServiceChar3 and AuthServiceChar5. And UserSertivce has a simple greet logic and actualized class is UserServiceDefaultUser and UserServiceNoDefault.

And Environment is case class which needs a user name, UserService, and AuthService. And here are some Reader Monad use environment and return something.

```import cats.data.Reader

}

}
// In Intellij if you use auto complete, Kleisli[Id, Environment, String] will be written. I will write post later
val resultR: Reader[Environment, String] = for {
logged <- isLoggedUser
greeting <- greetUser(logged)
} yield greeting
```

Value resultR is a Reader Monad get logged value from isLoggedUser and return greet String.

In here yet, we didn’t pass Environment instance. Now, let’s pass Environment.

```
val environment1 = Environment("Joe", new UserServiceDefaultUser, new AuthServiceChar3)

println(resultR.run(environment1))  // print Hello Joe

val environment2 = Environment("Joe", new UserServiceNoDefault, new AuthServiceChar5)

println(resultR.run(environment2))  // print No authorization

```

As you can see, we inject environment when we call run function. And when we inject different instance, print different output.

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
 trait AuthService { def isLogged(name: String): Boolean } class AuthServiceChar3 extends AuthService{ override def isLogged(name: String): Boolean = name.length == 3 } class AuthServiceChar5 extends AuthService{ override def isLogged(name: String): Boolean = name.length == 5 } trait UserService { def greet(name: String, isLogged: Boolean): String } class UserServiceDefaultUser extends UserService{ override def greet(name: String, isLogged: Boolean): String = { val actualName = if(isLogged) name else "User" s"Hello \$actualName" } } class UserServiceNoDefault extends UserService{ override def greet(name: String, isLogged: Boolean): String = { if(isLogged) s"Hello \$name" else "No authorization" } } case class Environment(userName: String, userService: UserService, authService: AuthService) import cats.data.Reader def isLoggedUser: Reader[Environment, Boolean] = Reader[Environment, Boolean] { env => env.authService.isLogged(env.userName) } def greetUser(logged: Boolean): Reader[Environment, String] = Reader[Environment, String] { env => env.userService.greet(env.userName, logged) } // In Intellij if you use auto complete, Kleisli[Id, Environment, String] will be written. I will write post later val resultR: Reader[Environment, String] = for { logged <- isLoggedUser greeting <- greetUser(logged) } yield greeting val environment1 = Environment("Joe", new UserServiceDefaultUser, new AuthServiceChar3) println(resultR.run(environment1)) val environment2 = Environment("Joe", new UserServiceNoDefault, new AuthServiceChar5) println(resultR.run(environment2))