you'll need a typeclass.. // we can't change the user, imagine from a library case class User(name: String, age: Int) // simplification trait Decoder[A] { def toJson(a: A): String } 1 https://github.com/circe/circe
define it! But we can for our own types now case class SortedUsers(users: List[User]) implicit val sortedByAgeMonoid = new Monoid[SortedUsers] { def empty: SortedUsers = SortedUsers(List.empty) def combine(a: SortedUsers, b: SortedUsers): SortedUsers = SortedUsers((a.users ::: b.users).sortBy(_.age)) } implicit val sortedByLexicographicOrderMonoid = new Monoid[SortedUsers] { def empty: SortedUsers = SortedUsers(List.empty) def combine(a: SortedUsers, b: SortedUsers): SortedUsers = SortedUsers((a.users ::: b.users).sortBy(_.name)) }
work for us • use it for existing stuff, like Map • define it when you want to combine your own types once and get everything else for free • define different versions of your Monoid
updateUser(user: User): User = ??? // db operations val maybeUser1: Option[User] = getUser(1) val updatedUser: Option[User] = maybeUser1.map(user1 => updateUser(user1))
updateUser(user: User): Option[User] = ??? // db operations def getUsersCity(user: User): Option[City] = ??? // db operations val optCity: Option[City] = for { user <- getUser(1) updateUser <- updateUser(user.change) city <- getUsersCity(updateUser) } yield city
// db operations def updateUser(user: User): M[User] = ??? // db operations def getUsersCity(user: User): M[City] = ??? // db operations } // M could be Option val optionMonad: Monad[Option]