diff --git a/commons/src/main/scala/io/github/tassiLuca/dse/examples/gears/ShowcasingDirectStyle.scala b/commons/src/main/scala/io/github/tassiLuca/dse/examples/gears/ShowcasingDirectStyle.scala new file mode 100644 index 00000000..ce534810 --- /dev/null +++ b/commons/src/main/scala/io/github/tassiLuca/dse/examples/gears/ShowcasingDirectStyle.scala @@ -0,0 +1,55 @@ +package io.github.tassiLuca.dse.examples.gears + +import scala.reflect.ClassTag + +object ShowcasingDirectStyle: + + object Monadic: + import scala.concurrent.duration.Duration + import scala.concurrent.{Await, ExecutionContext, Future} + + def transform[E, T]( + xs: Seq[Future[Either[E, T]]], + )(using ExecutionContext): Future[Either[E, Seq[T]]] = + import cats.implicits._ + Future.sequence(xs) // Future[Seq[Either[E, T]] + .map(_.sequence) // equivalent to: _.traverse(identity) + + def transform2[E, T]( + xs: Seq[Future[Either[E, T]]], + )(using ec: ExecutionContext): Future[Either[E, Seq[T]]] = + val initial: Future[Either[E, List[T]]] = Future.successful(Right(List.empty[T])) + xs.foldRight(initial): (future, acc) => + for + f <- future + a <- acc + yield a.flatMap(lst => f.map(_ :: lst)) + + @main def useMonadicTransform(): Unit = + given ExecutionContext = ExecutionContext.global + val xs = Seq(Future(Right("I")), Future(Right("Love")), Future(Right("Monads"))) + val result = transform(xs) // transform 2 works as well + println(Await.result(result, Duration.Inf)) + val ys = Seq(Future(Right("Yes")), Future(Left("Nope!"))) + val result2 = transform(ys) // transform 2 works as well + println(Await.result(result2, Duration.Inf)) + + object Direct: + import gears.async.default.given + import gears.async.{Future, Async} + import io.github.tassiLuca.dse.boundaries.either + import io.github.tassiLuca.dse.boundaries.either.? + import io.github.tassiLuca.dse.boundaries.EitherConversions.given + + def transform[E, T](xs: Seq[Future[Either[E, T]]])(using Async.Spawn): Future[Either[E, Seq[T]]] = + Future: + either: + xs.map(_.await.?) + + @main def useDirectTransform(): Unit = Async.blocking: + val xs = Seq(Future(Right("I")), Future(Right("Love")), Future(Right("Monads"))) + val result = transform(xs) + println(result.await) + val ys = Seq(Future(Right("Yes")), Future(Left("Nope!"))) + val result2 = transform(ys) + println(result2.await) diff --git a/docs/presentation/direct-style-presentation.tex b/docs/presentation/direct-style-presentation.tex index 8eb3a1f8..24ef7604 100644 --- a/docs/presentation/direct-style-presentation.tex +++ b/docs/presentation/direct-style-presentation.tex @@ -287,6 +287,25 @@ \section{Scala \texttt{gears}} \end{table} \end{frame} % +\begin{frame} + \small + \begin{columns} + \column{0.6\textwidth} + \lstinputlisting[language=scala]{listings/intro/DirectComposability.scala} + \column{0.2\textwidth} + Direct style cleanly supports composability. + \end{columns} + + \pause + \begin{columns} + \column{0.91\textwidth} + \lstinputlisting[language=scala]{listings/intro/MonadicComposability.scala} + \lstinputlisting[language=scala]{listings/intro/IdiomaticMonadicComposability.scala} + \column{0.1\textwidth} + Using monads is more complex to achieve the same goal. + \end{columns} +\end{frame} +% \begin{frame} \begin{columns}[c,onlytextwidth] % The "t" option specifies top vertical alignment \column{.35\textwidth} diff --git a/docs/presentation/listings/intro/DirectComposability.scala b/docs/presentation/listings/intro/DirectComposability.scala new file mode 100644 index 00000000..97e3fe59 --- /dev/null +++ b/docs/presentation/listings/intro/DirectComposability.scala @@ -0,0 +1,6 @@ +def transform[E, T]( + xs: Seq[Future[Either[E, T]]] +)(using Async.Spawn): Future[Either[E, Seq[T]]] = + Future: + either: + xs.map(_.await.?) \ No newline at end of file diff --git a/docs/presentation/listings/intro/IdiomaticMonadicComposability.scala b/docs/presentation/listings/intro/IdiomaticMonadicComposability.scala new file mode 100644 index 00000000..f55b15a6 --- /dev/null +++ b/docs/presentation/listings/intro/IdiomaticMonadicComposability.scala @@ -0,0 +1,6 @@ +def transform[E, T]( + xs: Seq[Future[Either[E, T]]], +)(using ExecutionContext): Future[Either[E, Seq[T]]] = + import cats.implicits._ + Future.sequence(xs) // Future[Seq[Either[E, T]] + .map(_.sequence) // equivalent to: _.traverse(identity) diff --git a/docs/presentation/listings/intro/MonadicComposability.scala b/docs/presentation/listings/intro/MonadicComposability.scala new file mode 100644 index 00000000..9905dee7 --- /dev/null +++ b/docs/presentation/listings/intro/MonadicComposability.scala @@ -0,0 +1,9 @@ +def transform2[E, T]( + xs: Seq[Future[Either[E, T]]], +)(using ec: ExecutionContext): Future[Either[E, Seq[T]]] = + val initial: Future[Either[E, List[T]]] = Future.successful(Right(List.empty[T])) + xs.foldRight(initial): (future, acc) => + for + f <- future + a <- acc + yield a.flatMap(lst => f.map(_ :: lst)) \ No newline at end of file