Skip to content

Commit

Permalink
Added WriterMonad example
Browse files Browse the repository at this point in the history
  • Loading branch information
thobson committed Feb 17, 2020
1 parent 17d8464 commit 0a20de1
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ lazy val root = (project in file(".")).
libraryDependencies ++= Seq(
cats,
monix,
logback,
scalaTest % Test,
)
)
Expand Down
1 change: 1 addition & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ object Dependencies {
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.2.0-M2"
lazy val cats = "org.typelevel" %% "cats-core" % "2.1.0"
lazy val monix = "io.monix" %% "monix" % "3.1.0"
lazy val logback = "ch.qos.logback" % "logback-classic" % "1.2.3"
}
16 changes: 16 additions & 0 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- On Windows machines setting withJansi to true enables ANSI
color code interpretation by the Jansi library. This requires
org.fusesource.jansi:jansi:1.8 on the class path. Note that
Unix-based operating systems such as Linux and Mac OS X
support ANSI color codes by default. -->
<withJansi>true</withJansi>
<encoder>
<pattern>%highlight(%-5level) %cyan(%X{hint}) %magenta(%X{correlationId}) - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
64 changes: 64 additions & 0 deletions src/main/scala/uk/co/tobyhobson/cats/WriterMonad.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package uk.co.tobyhobson.cats

import cats.data.WriterT
import cats.instances.vector._
import ch.qos.logback.classic.Logger
import monix.eval.Task
import org.slf4j.LoggerFactory
import org.slf4j.event.Level

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

object WriterMonad {

private val Logger = LoggerFactory.getLogger(this.getClass)

case class User(id: Int)
case class Order(totalAmount: Int)

case class LogEntry(level: Level, message: String)

def getUser(id: Int): WriterT[Task, Vector[LogEntry], User] = {
val logs = Task(Vector(LogEntry(Level.DEBUG, "getting user")))
val withResult = logs.map(logs => logs -> User(id))
// The apply method is a simple way of constructing a writer with a log and result, suspended in F
WriterT(withResult)
}

def getOrder(user: User): WriterT[Task, Vector[LogEntry], Order] = {
val logs = Task(Vector(LogEntry(Level.DEBUG, "getting order")))
val withResult = logs.map(logs => logs -> Order(100))
WriterT(withResult)
}

def writeLogs(logs: Vector[LogEntry]): Task[Unit] = Task {
logs.foreach {
case LogEntry(Level.DEBUG, message) => Logger.debug(message)
case LogEntry(Level.INFO, message) => Logger.info(message)
// don't do this in production!
case LogEntry(_, message) => Logger.debug(message)
}
}

def main(args: Array[String]): Unit = {
import monix.execution.Scheduler.Implicits.global

val program = for {
user <- getUser(1)
order <- getOrder(user)
} yield order

val logged = for {
logs <- program.written
result <- program.value
_ <- writeLogs(logs)
} yield result

val eventualResult = logged.runToFuture
val result = Await.result(eventualResult, 1.second)

Logger.info(result.toString)
}

}

0 comments on commit 0a20de1

Please sign in to comment.